1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2013-2016 Qlogic Corporation
5 * All rights reserved.
6 *
7 *  Redistribution and use in source and binary forms, with or without
8 *  modification, are permitted provided that the following conditions
9 *  are met:
10 *
11 *  1. Redistributions of source code must retain the above copyright
12 *     notice, this list of conditions and the following disclaimer.
13 *  2. Redistributions in binary form must reproduce the above copyright
14 *     notice, this list of conditions and the following disclaimer in the
15 *     documentation and/or other materials provided with the distribution.
16 *
17 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 *  POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/*
31 * File: ql_hw.c
32 * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656.
33 * Content: Contains Hardware dependent functions
34 */
35
36#include <sys/cdefs.h>
37#include "ql_os.h"
38#include "ql_hw.h"
39#include "ql_def.h"
40#include "ql_inline.h"
41#include "ql_ver.h"
42#include "ql_glbl.h"
43#include "ql_dbg.h"
44#include "ql_minidump.h"
45
46/*
47 * Static Functions
48 */
49
50static void qla_del_rcv_cntxt(qla_host_t *ha);
51static int qla_init_rcv_cntxt(qla_host_t *ha);
52static int qla_del_xmt_cntxt(qla_host_t *ha);
53static int qla_init_xmt_cntxt(qla_host_t *ha);
54static int qla_mbx_cmd(qla_host_t *ha, uint32_t *h_mbox, uint32_t n_hmbox,
55	uint32_t *fw_mbox, uint32_t n_fwmbox, uint32_t no_pause);
56static int qla_config_intr_cntxt(qla_host_t *ha, uint32_t start_idx,
57	uint32_t num_intrs, uint32_t create);
58static int qla_config_rss(qla_host_t *ha, uint16_t cntxt_id);
59static int qla_config_intr_coalesce(qla_host_t *ha, uint16_t cntxt_id,
60	int tenable, int rcv);
61static int qla_set_mac_rcv_mode(qla_host_t *ha, uint32_t mode);
62static int qla_link_event_req(qla_host_t *ha, uint16_t cntxt_id);
63
64static int qla_tx_tso(qla_host_t *ha, struct mbuf *mp, q80_tx_cmd_t *tx_cmd,
65		uint8_t *hdr);
66static int qla_hw_add_all_mcast(qla_host_t *ha);
67static int qla_add_rcv_rings(qla_host_t *ha, uint32_t sds_idx, uint32_t nsds);
68
69static int qla_init_nic_func(qla_host_t *ha);
70static int qla_stop_nic_func(qla_host_t *ha);
71static int qla_query_fw_dcbx_caps(qla_host_t *ha);
72static int qla_set_port_config(qla_host_t *ha, uint32_t cfg_bits);
73static int qla_get_port_config(qla_host_t *ha, uint32_t *cfg_bits);
74static int qla_set_cam_search_mode(qla_host_t *ha, uint32_t search_mode);
75static int qla_get_cam_search_mode(qla_host_t *ha);
76
77static void ql_minidump_free(qla_host_t *ha);
78
79#ifdef QL_DBG
80
81static void
82qla_stop_pegs(qla_host_t *ha)
83{
84        uint32_t val = 1;
85
86        ql_rdwr_indreg32(ha, Q8_CRB_PEG_0, &val, 0);
87        ql_rdwr_indreg32(ha, Q8_CRB_PEG_1, &val, 0);
88        ql_rdwr_indreg32(ha, Q8_CRB_PEG_2, &val, 0);
89        ql_rdwr_indreg32(ha, Q8_CRB_PEG_3, &val, 0);
90        ql_rdwr_indreg32(ha, Q8_CRB_PEG_4, &val, 0);
91        device_printf(ha->pci_dev, "%s PEGS HALTED!!!!!\n", __func__);
92}
93
94static int
95qla_sysctl_stop_pegs(SYSCTL_HANDLER_ARGS)
96{
97	int err, ret = 0;
98	qla_host_t *ha;
99
100	err = sysctl_handle_int(oidp, &ret, 0, req);
101
102	if (err || !req->newptr)
103		return (err);
104
105	if (ret == 1) {
106		ha = (qla_host_t *)arg1;
107		if (QLA_LOCK(ha, __func__, QLA_LOCK_DEFAULT_MS_TIMEOUT, 0) == 0) {
108			qla_stop_pegs(ha);
109			QLA_UNLOCK(ha, __func__);
110		}
111	}
112
113	return err;
114}
115#endif /* #ifdef QL_DBG */
116
117static int
118qla_validate_set_port_cfg_bit(uint32_t bits)
119{
120        if ((bits & 0xF) > 1)
121                return (-1);
122
123        if (((bits >> 4) & 0xF) > 2)
124                return (-1);
125
126        if (((bits >> 8) & 0xF) > 2)
127                return (-1);
128
129        return (0);
130}
131
132static int
133qla_sysctl_port_cfg(SYSCTL_HANDLER_ARGS)
134{
135        int err, ret = 0;
136        qla_host_t *ha;
137        uint32_t cfg_bits;
138
139        err = sysctl_handle_int(oidp, &ret, 0, req);
140
141        if (err || !req->newptr)
142                return (err);
143
144	ha = (qla_host_t *)arg1;
145
146        if ((qla_validate_set_port_cfg_bit((uint32_t)ret) == 0)) {
147                err = qla_get_port_config(ha, &cfg_bits);
148
149                if (err)
150                        goto qla_sysctl_set_port_cfg_exit;
151
152                if (ret & 0x1) {
153                        cfg_bits |= Q8_PORT_CFG_BITS_DCBX_ENABLE;
154                } else {
155                        cfg_bits &= ~Q8_PORT_CFG_BITS_DCBX_ENABLE;
156                }
157
158                ret = ret >> 4;
159                cfg_bits &= ~Q8_PORT_CFG_BITS_PAUSE_CFG_MASK;
160
161                if ((ret & 0xF) == 0) {
162                        cfg_bits |= Q8_PORT_CFG_BITS_PAUSE_DISABLED;
163                } else if ((ret & 0xF) == 1){
164                        cfg_bits |= Q8_PORT_CFG_BITS_PAUSE_STD;
165                } else {
166                        cfg_bits |= Q8_PORT_CFG_BITS_PAUSE_PPM;
167                }
168
169                ret = ret >> 4;
170                cfg_bits &= ~Q8_PORT_CFG_BITS_STDPAUSE_DIR_MASK;
171
172                if (ret == 0) {
173                        cfg_bits |= Q8_PORT_CFG_BITS_STDPAUSE_XMT_RCV;
174                } else if (ret == 1){
175                        cfg_bits |= Q8_PORT_CFG_BITS_STDPAUSE_XMT;
176                } else {
177                        cfg_bits |= Q8_PORT_CFG_BITS_STDPAUSE_RCV;
178                }
179
180		if (QLA_LOCK(ha, __func__, QLA_LOCK_DEFAULT_MS_TIMEOUT, 0) == 0) {
181                	err = qla_set_port_config(ha, cfg_bits);
182			QLA_UNLOCK(ha, __func__);
183		} else {
184			device_printf(ha->pci_dev, "%s: failed\n", __func__);
185		}
186        } else {
187		if (QLA_LOCK(ha, __func__, QLA_LOCK_DEFAULT_MS_TIMEOUT, 0) == 0) {
188                	err = qla_get_port_config(ha, &cfg_bits);
189			QLA_UNLOCK(ha, __func__);
190		} else {
191			device_printf(ha->pci_dev, "%s: failed\n", __func__);
192		}
193        }
194
195qla_sysctl_set_port_cfg_exit:
196        return err;
197}
198
199static int
200qla_sysctl_set_cam_search_mode(SYSCTL_HANDLER_ARGS)
201{
202	int err, ret = 0;
203	qla_host_t *ha;
204
205	err = sysctl_handle_int(oidp, &ret, 0, req);
206
207	if (err || !req->newptr)
208		return (err);
209
210	ha = (qla_host_t *)arg1;
211
212	if ((ret == Q8_HW_CONFIG_CAM_SEARCH_MODE_INTERNAL) ||
213		(ret == Q8_HW_CONFIG_CAM_SEARCH_MODE_AUTO)) {
214		if (QLA_LOCK(ha, __func__, QLA_LOCK_DEFAULT_MS_TIMEOUT, 0) == 0) {
215			err = qla_set_cam_search_mode(ha, (uint32_t)ret);
216			QLA_UNLOCK(ha, __func__);
217		} else {
218			device_printf(ha->pci_dev, "%s: failed\n", __func__);
219		}
220
221	} else {
222		device_printf(ha->pci_dev, "%s: ret = %d\n", __func__, ret);
223	}
224
225	return (err);
226}
227
228static int
229qla_sysctl_get_cam_search_mode(SYSCTL_HANDLER_ARGS)
230{
231	int err, ret = 0;
232	qla_host_t *ha;
233
234	err = sysctl_handle_int(oidp, &ret, 0, req);
235
236	if (err || !req->newptr)
237		return (err);
238
239	ha = (qla_host_t *)arg1;
240	if (QLA_LOCK(ha, __func__, QLA_LOCK_DEFAULT_MS_TIMEOUT, 0) == 0) {
241		err = qla_get_cam_search_mode(ha);
242		QLA_UNLOCK(ha, __func__);
243	} else {
244		device_printf(ha->pci_dev, "%s: failed\n", __func__);
245	}
246
247	return (err);
248}
249
250static void
251qlnx_add_hw_mac_stats_sysctls(qla_host_t *ha)
252{
253        struct sysctl_ctx_list  *ctx;
254        struct sysctl_oid_list  *children;
255        struct sysctl_oid       *ctx_oid;
256
257        ctx = device_get_sysctl_ctx(ha->pci_dev);
258        children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev));
259
260        ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats_hw_mac",
261	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "stats_hw_mac");
262        children = SYSCTL_CHILDREN(ctx_oid);
263
264        SYSCTL_ADD_QUAD(ctx, children,
265                OID_AUTO, "xmt_frames",
266                CTLFLAG_RD, &ha->hw.mac.xmt_frames,
267                "xmt_frames");
268
269        SYSCTL_ADD_QUAD(ctx, children,
270                OID_AUTO, "xmt_bytes",
271                CTLFLAG_RD, &ha->hw.mac.xmt_bytes,
272                "xmt_frames");
273
274        SYSCTL_ADD_QUAD(ctx, children,
275                OID_AUTO, "xmt_mcast_pkts",
276                CTLFLAG_RD, &ha->hw.mac.xmt_mcast_pkts,
277                "xmt_mcast_pkts");
278
279        SYSCTL_ADD_QUAD(ctx, children,
280                OID_AUTO, "xmt_bcast_pkts",
281                CTLFLAG_RD, &ha->hw.mac.xmt_bcast_pkts,
282                "xmt_bcast_pkts");
283
284        SYSCTL_ADD_QUAD(ctx, children,
285                OID_AUTO, "xmt_pause_frames",
286                CTLFLAG_RD, &ha->hw.mac.xmt_pause_frames,
287                "xmt_pause_frames");
288
289        SYSCTL_ADD_QUAD(ctx, children,
290                OID_AUTO, "xmt_cntrl_pkts",
291                CTLFLAG_RD, &ha->hw.mac.xmt_cntrl_pkts,
292                "xmt_cntrl_pkts");
293
294        SYSCTL_ADD_QUAD(ctx, children,
295                OID_AUTO, "xmt_pkt_lt_64bytes",
296                CTLFLAG_RD, &ha->hw.mac.xmt_pkt_lt_64bytes,
297                "xmt_pkt_lt_64bytes");
298
299        SYSCTL_ADD_QUAD(ctx, children,
300                OID_AUTO, "xmt_pkt_lt_127bytes",
301                CTLFLAG_RD, &ha->hw.mac.xmt_pkt_lt_127bytes,
302                "xmt_pkt_lt_127bytes");
303
304        SYSCTL_ADD_QUAD(ctx, children,
305                OID_AUTO, "xmt_pkt_lt_255bytes",
306                CTLFLAG_RD, &ha->hw.mac.xmt_pkt_lt_255bytes,
307                "xmt_pkt_lt_255bytes");
308
309        SYSCTL_ADD_QUAD(ctx, children,
310                OID_AUTO, "xmt_pkt_lt_511bytes",
311                CTLFLAG_RD, &ha->hw.mac.xmt_pkt_lt_511bytes,
312                "xmt_pkt_lt_511bytes");
313
314        SYSCTL_ADD_QUAD(ctx, children,
315                OID_AUTO, "xmt_pkt_lt_1023bytes",
316                CTLFLAG_RD, &ha->hw.mac.xmt_pkt_lt_1023bytes,
317                "xmt_pkt_lt_1023bytes");
318
319        SYSCTL_ADD_QUAD(ctx, children,
320                OID_AUTO, "xmt_pkt_lt_1518bytes",
321                CTLFLAG_RD, &ha->hw.mac.xmt_pkt_lt_1518bytes,
322                "xmt_pkt_lt_1518bytes");
323
324        SYSCTL_ADD_QUAD(ctx, children,
325                OID_AUTO, "xmt_pkt_gt_1518bytes",
326                CTLFLAG_RD, &ha->hw.mac.xmt_pkt_gt_1518bytes,
327                "xmt_pkt_gt_1518bytes");
328
329        SYSCTL_ADD_QUAD(ctx, children,
330                OID_AUTO, "rcv_frames",
331                CTLFLAG_RD, &ha->hw.mac.rcv_frames,
332                "rcv_frames");
333
334        SYSCTL_ADD_QUAD(ctx, children,
335                OID_AUTO, "rcv_bytes",
336                CTLFLAG_RD, &ha->hw.mac.rcv_bytes,
337                "rcv_bytes");
338
339        SYSCTL_ADD_QUAD(ctx, children,
340                OID_AUTO, "rcv_mcast_pkts",
341                CTLFLAG_RD, &ha->hw.mac.rcv_mcast_pkts,
342                "rcv_mcast_pkts");
343
344        SYSCTL_ADD_QUAD(ctx, children,
345                OID_AUTO, "rcv_bcast_pkts",
346                CTLFLAG_RD, &ha->hw.mac.rcv_bcast_pkts,
347                "rcv_bcast_pkts");
348
349        SYSCTL_ADD_QUAD(ctx, children,
350                OID_AUTO, "rcv_pause_frames",
351                CTLFLAG_RD, &ha->hw.mac.rcv_pause_frames,
352                "rcv_pause_frames");
353
354        SYSCTL_ADD_QUAD(ctx, children,
355                OID_AUTO, "rcv_cntrl_pkts",
356                CTLFLAG_RD, &ha->hw.mac.rcv_cntrl_pkts,
357                "rcv_cntrl_pkts");
358
359        SYSCTL_ADD_QUAD(ctx, children,
360                OID_AUTO, "rcv_pkt_lt_64bytes",
361                CTLFLAG_RD, &ha->hw.mac.rcv_pkt_lt_64bytes,
362                "rcv_pkt_lt_64bytes");
363
364        SYSCTL_ADD_QUAD(ctx, children,
365                OID_AUTO, "rcv_pkt_lt_127bytes",
366                CTLFLAG_RD, &ha->hw.mac.rcv_pkt_lt_127bytes,
367                "rcv_pkt_lt_127bytes");
368
369        SYSCTL_ADD_QUAD(ctx, children,
370                OID_AUTO, "rcv_pkt_lt_255bytes",
371                CTLFLAG_RD, &ha->hw.mac.rcv_pkt_lt_255bytes,
372                "rcv_pkt_lt_255bytes");
373
374        SYSCTL_ADD_QUAD(ctx, children,
375                OID_AUTO, "rcv_pkt_lt_511bytes",
376                CTLFLAG_RD, &ha->hw.mac.rcv_pkt_lt_511bytes,
377                "rcv_pkt_lt_511bytes");
378
379        SYSCTL_ADD_QUAD(ctx, children,
380                OID_AUTO, "rcv_pkt_lt_1023bytes",
381                CTLFLAG_RD, &ha->hw.mac.rcv_pkt_lt_1023bytes,
382                "rcv_pkt_lt_1023bytes");
383
384        SYSCTL_ADD_QUAD(ctx, children,
385                OID_AUTO, "rcv_pkt_lt_1518bytes",
386                CTLFLAG_RD, &ha->hw.mac.rcv_pkt_lt_1518bytes,
387                "rcv_pkt_lt_1518bytes");
388
389        SYSCTL_ADD_QUAD(ctx, children,
390                OID_AUTO, "rcv_pkt_gt_1518bytes",
391                CTLFLAG_RD, &ha->hw.mac.rcv_pkt_gt_1518bytes,
392                "rcv_pkt_gt_1518bytes");
393
394        SYSCTL_ADD_QUAD(ctx, children,
395                OID_AUTO, "rcv_len_error",
396                CTLFLAG_RD, &ha->hw.mac.rcv_len_error,
397                "rcv_len_error");
398
399        SYSCTL_ADD_QUAD(ctx, children,
400                OID_AUTO, "rcv_len_small",
401                CTLFLAG_RD, &ha->hw.mac.rcv_len_small,
402                "rcv_len_small");
403
404        SYSCTL_ADD_QUAD(ctx, children,
405                OID_AUTO, "rcv_len_large",
406                CTLFLAG_RD, &ha->hw.mac.rcv_len_large,
407                "rcv_len_large");
408
409        SYSCTL_ADD_QUAD(ctx, children,
410                OID_AUTO, "rcv_jabber",
411                CTLFLAG_RD, &ha->hw.mac.rcv_jabber,
412                "rcv_jabber");
413
414        SYSCTL_ADD_QUAD(ctx, children,
415                OID_AUTO, "rcv_dropped",
416                CTLFLAG_RD, &ha->hw.mac.rcv_dropped,
417                "rcv_dropped");
418
419        SYSCTL_ADD_QUAD(ctx, children,
420                OID_AUTO, "fcs_error",
421                CTLFLAG_RD, &ha->hw.mac.fcs_error,
422                "fcs_error");
423
424        SYSCTL_ADD_QUAD(ctx, children,
425                OID_AUTO, "align_error",
426                CTLFLAG_RD, &ha->hw.mac.align_error,
427                "align_error");
428
429        SYSCTL_ADD_QUAD(ctx, children,
430                OID_AUTO, "eswitched_frames",
431                CTLFLAG_RD, &ha->hw.mac.eswitched_frames,
432                "eswitched_frames");
433
434        SYSCTL_ADD_QUAD(ctx, children,
435                OID_AUTO, "eswitched_bytes",
436                CTLFLAG_RD, &ha->hw.mac.eswitched_bytes,
437                "eswitched_bytes");
438
439        SYSCTL_ADD_QUAD(ctx, children,
440                OID_AUTO, "eswitched_mcast_frames",
441                CTLFLAG_RD, &ha->hw.mac.eswitched_mcast_frames,
442                "eswitched_mcast_frames");
443
444        SYSCTL_ADD_QUAD(ctx, children,
445                OID_AUTO, "eswitched_bcast_frames",
446                CTLFLAG_RD, &ha->hw.mac.eswitched_bcast_frames,
447                "eswitched_bcast_frames");
448
449        SYSCTL_ADD_QUAD(ctx, children,
450                OID_AUTO, "eswitched_ucast_frames",
451                CTLFLAG_RD, &ha->hw.mac.eswitched_ucast_frames,
452                "eswitched_ucast_frames");
453
454        SYSCTL_ADD_QUAD(ctx, children,
455                OID_AUTO, "eswitched_err_free_frames",
456                CTLFLAG_RD, &ha->hw.mac.eswitched_err_free_frames,
457                "eswitched_err_free_frames");
458
459        SYSCTL_ADD_QUAD(ctx, children,
460                OID_AUTO, "eswitched_err_free_bytes",
461                CTLFLAG_RD, &ha->hw.mac.eswitched_err_free_bytes,
462                "eswitched_err_free_bytes");
463
464	return;
465}
466
467static void
468qlnx_add_hw_rcv_stats_sysctls(qla_host_t *ha)
469{
470        struct sysctl_ctx_list  *ctx;
471        struct sysctl_oid_list  *children;
472        struct sysctl_oid       *ctx_oid;
473
474        ctx = device_get_sysctl_ctx(ha->pci_dev);
475        children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev));
476
477        ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats_hw_rcv",
478	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "stats_hw_rcv");
479        children = SYSCTL_CHILDREN(ctx_oid);
480
481        SYSCTL_ADD_QUAD(ctx, children,
482                OID_AUTO, "total_bytes",
483                CTLFLAG_RD, &ha->hw.rcv.total_bytes,
484                "total_bytes");
485
486        SYSCTL_ADD_QUAD(ctx, children,
487                OID_AUTO, "total_pkts",
488                CTLFLAG_RD, &ha->hw.rcv.total_pkts,
489                "total_pkts");
490
491        SYSCTL_ADD_QUAD(ctx, children,
492                OID_AUTO, "lro_pkt_count",
493                CTLFLAG_RD, &ha->hw.rcv.lro_pkt_count,
494                "lro_pkt_count");
495
496        SYSCTL_ADD_QUAD(ctx, children,
497                OID_AUTO, "sw_pkt_count",
498                CTLFLAG_RD, &ha->hw.rcv.sw_pkt_count,
499                "sw_pkt_count");
500
501        SYSCTL_ADD_QUAD(ctx, children,
502                OID_AUTO, "ip_chksum_err",
503                CTLFLAG_RD, &ha->hw.rcv.ip_chksum_err,
504                "ip_chksum_err");
505
506        SYSCTL_ADD_QUAD(ctx, children,
507                OID_AUTO, "pkts_wo_acntxts",
508                CTLFLAG_RD, &ha->hw.rcv.pkts_wo_acntxts,
509                "pkts_wo_acntxts");
510
511        SYSCTL_ADD_QUAD(ctx, children,
512                OID_AUTO, "pkts_dropped_no_sds_card",
513                CTLFLAG_RD, &ha->hw.rcv.pkts_dropped_no_sds_card,
514                "pkts_dropped_no_sds_card");
515
516        SYSCTL_ADD_QUAD(ctx, children,
517                OID_AUTO, "pkts_dropped_no_sds_host",
518                CTLFLAG_RD, &ha->hw.rcv.pkts_dropped_no_sds_host,
519                "pkts_dropped_no_sds_host");
520
521        SYSCTL_ADD_QUAD(ctx, children,
522                OID_AUTO, "oversized_pkts",
523                CTLFLAG_RD, &ha->hw.rcv.oversized_pkts,
524                "oversized_pkts");
525
526        SYSCTL_ADD_QUAD(ctx, children,
527                OID_AUTO, "pkts_dropped_no_rds",
528                CTLFLAG_RD, &ha->hw.rcv.pkts_dropped_no_rds,
529                "pkts_dropped_no_rds");
530
531        SYSCTL_ADD_QUAD(ctx, children,
532                OID_AUTO, "unxpctd_mcast_pkts",
533                CTLFLAG_RD, &ha->hw.rcv.unxpctd_mcast_pkts,
534                "unxpctd_mcast_pkts");
535
536        SYSCTL_ADD_QUAD(ctx, children,
537                OID_AUTO, "re1_fbq_error",
538                CTLFLAG_RD, &ha->hw.rcv.re1_fbq_error,
539                "re1_fbq_error");
540
541        SYSCTL_ADD_QUAD(ctx, children,
542                OID_AUTO, "invalid_mac_addr",
543                CTLFLAG_RD, &ha->hw.rcv.invalid_mac_addr,
544                "invalid_mac_addr");
545
546        SYSCTL_ADD_QUAD(ctx, children,
547                OID_AUTO, "rds_prime_trys",
548                CTLFLAG_RD, &ha->hw.rcv.rds_prime_trys,
549                "rds_prime_trys");
550
551        SYSCTL_ADD_QUAD(ctx, children,
552                OID_AUTO, "rds_prime_success",
553                CTLFLAG_RD, &ha->hw.rcv.rds_prime_success,
554                "rds_prime_success");
555
556        SYSCTL_ADD_QUAD(ctx, children,
557                OID_AUTO, "lro_flows_added",
558                CTLFLAG_RD, &ha->hw.rcv.lro_flows_added,
559                "lro_flows_added");
560
561        SYSCTL_ADD_QUAD(ctx, children,
562                OID_AUTO, "lro_flows_deleted",
563                CTLFLAG_RD, &ha->hw.rcv.lro_flows_deleted,
564                "lro_flows_deleted");
565
566        SYSCTL_ADD_QUAD(ctx, children,
567                OID_AUTO, "lro_flows_active",
568                CTLFLAG_RD, &ha->hw.rcv.lro_flows_active,
569                "lro_flows_active");
570
571        SYSCTL_ADD_QUAD(ctx, children,
572                OID_AUTO, "pkts_droped_unknown",
573                CTLFLAG_RD, &ha->hw.rcv.pkts_droped_unknown,
574                "pkts_droped_unknown");
575
576        SYSCTL_ADD_QUAD(ctx, children,
577                OID_AUTO, "pkts_cnt_oversized",
578                CTLFLAG_RD, &ha->hw.rcv.pkts_cnt_oversized,
579                "pkts_cnt_oversized");
580
581	return;
582}
583
584static void
585qlnx_add_hw_xmt_stats_sysctls(qla_host_t *ha)
586{
587        struct sysctl_ctx_list  *ctx;
588        struct sysctl_oid_list  *children;
589        struct sysctl_oid_list  *node_children;
590        struct sysctl_oid       *ctx_oid;
591        int                     i;
592        uint8_t                 name_str[16];
593
594        ctx = device_get_sysctl_ctx(ha->pci_dev);
595        children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev));
596
597        ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats_hw_xmt",
598	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "stats_hw_xmt");
599        children = SYSCTL_CHILDREN(ctx_oid);
600
601        for (i = 0; i < ha->hw.num_tx_rings; i++) {
602                bzero(name_str, (sizeof(uint8_t) * sizeof(name_str)));
603                snprintf(name_str, sizeof(name_str), "%d", i);
604
605                ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, name_str,
606                    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, name_str);
607                node_children = SYSCTL_CHILDREN(ctx_oid);
608
609                /* Tx Related */
610
611                SYSCTL_ADD_QUAD(ctx, node_children,
612			OID_AUTO, "total_bytes",
613                        CTLFLAG_RD, &ha->hw.xmt[i].total_bytes,
614                        "total_bytes");
615
616                SYSCTL_ADD_QUAD(ctx, node_children,
617			OID_AUTO, "total_pkts",
618                        CTLFLAG_RD, &ha->hw.xmt[i].total_pkts,
619                        "total_pkts");
620
621                SYSCTL_ADD_QUAD(ctx, node_children,
622			OID_AUTO, "errors",
623                        CTLFLAG_RD, &ha->hw.xmt[i].errors,
624                        "errors");
625
626                SYSCTL_ADD_QUAD(ctx, node_children,
627			OID_AUTO, "pkts_dropped",
628                        CTLFLAG_RD, &ha->hw.xmt[i].pkts_dropped,
629                        "pkts_dropped");
630
631                SYSCTL_ADD_QUAD(ctx, node_children,
632			OID_AUTO, "switch_pkts",
633                        CTLFLAG_RD, &ha->hw.xmt[i].switch_pkts,
634                        "switch_pkts");
635
636                SYSCTL_ADD_QUAD(ctx, node_children,
637			OID_AUTO, "num_buffers",
638                        CTLFLAG_RD, &ha->hw.xmt[i].num_buffers,
639                        "num_buffers");
640	}
641
642	return;
643}
644
645static void
646qlnx_add_hw_mbx_cmpl_stats_sysctls(qla_host_t *ha)
647{
648        struct sysctl_ctx_list  *ctx;
649        struct sysctl_oid_list  *node_children;
650
651        ctx = device_get_sysctl_ctx(ha->pci_dev);
652        node_children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev));
653
654	SYSCTL_ADD_QUAD(ctx, node_children,
655		OID_AUTO, "mbx_completion_time_lt_200ms",
656		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[0],
657		"mbx_completion_time_lt_200ms");
658
659	SYSCTL_ADD_QUAD(ctx, node_children,
660		OID_AUTO, "mbx_completion_time_200ms_400ms",
661		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[1],
662		"mbx_completion_time_200ms_400ms");
663
664	SYSCTL_ADD_QUAD(ctx, node_children,
665		OID_AUTO, "mbx_completion_time_400ms_600ms",
666		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[2],
667		"mbx_completion_time_400ms_600ms");
668
669	SYSCTL_ADD_QUAD(ctx, node_children,
670		OID_AUTO, "mbx_completion_time_600ms_800ms",
671		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[3],
672		"mbx_completion_time_600ms_800ms");
673
674	SYSCTL_ADD_QUAD(ctx, node_children,
675		OID_AUTO, "mbx_completion_time_800ms_1000ms",
676		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[4],
677		"mbx_completion_time_800ms_1000ms");
678
679	SYSCTL_ADD_QUAD(ctx, node_children,
680		OID_AUTO, "mbx_completion_time_1000ms_1200ms",
681		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[5],
682		"mbx_completion_time_1000ms_1200ms");
683
684	SYSCTL_ADD_QUAD(ctx, node_children,
685		OID_AUTO, "mbx_completion_time_1200ms_1400ms",
686		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[6],
687		"mbx_completion_time_1200ms_1400ms");
688
689	SYSCTL_ADD_QUAD(ctx, node_children,
690		OID_AUTO, "mbx_completion_time_1400ms_1600ms",
691		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[7],
692		"mbx_completion_time_1400ms_1600ms");
693
694	SYSCTL_ADD_QUAD(ctx, node_children,
695		OID_AUTO, "mbx_completion_time_1600ms_1800ms",
696		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[8],
697		"mbx_completion_time_1600ms_1800ms");
698
699	SYSCTL_ADD_QUAD(ctx, node_children,
700		OID_AUTO, "mbx_completion_time_1800ms_2000ms",
701		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[9],
702		"mbx_completion_time_1800ms_2000ms");
703
704	SYSCTL_ADD_QUAD(ctx, node_children,
705		OID_AUTO, "mbx_completion_time_2000ms_2200ms",
706		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[10],
707		"mbx_completion_time_2000ms_2200ms");
708
709	SYSCTL_ADD_QUAD(ctx, node_children,
710		OID_AUTO, "mbx_completion_time_2200ms_2400ms",
711		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[11],
712		"mbx_completion_time_2200ms_2400ms");
713
714	SYSCTL_ADD_QUAD(ctx, node_children,
715		OID_AUTO, "mbx_completion_time_2400ms_2600ms",
716		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[12],
717		"mbx_completion_time_2400ms_2600ms");
718
719	SYSCTL_ADD_QUAD(ctx, node_children,
720		OID_AUTO, "mbx_completion_time_2600ms_2800ms",
721		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[13],
722		"mbx_completion_time_2600ms_2800ms");
723
724	SYSCTL_ADD_QUAD(ctx, node_children,
725		OID_AUTO, "mbx_completion_time_2800ms_3000ms",
726		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[14],
727		"mbx_completion_time_2800ms_3000ms");
728
729	SYSCTL_ADD_QUAD(ctx, node_children,
730		OID_AUTO, "mbx_completion_time_3000ms_4000ms",
731		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[15],
732		"mbx_completion_time_3000ms_4000ms");
733
734	SYSCTL_ADD_QUAD(ctx, node_children,
735		OID_AUTO, "mbx_completion_time_4000ms_5000ms",
736		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[16],
737		"mbx_completion_time_4000ms_5000ms");
738
739	SYSCTL_ADD_QUAD(ctx, node_children,
740		OID_AUTO, "mbx_completion_host_mbx_cntrl_timeout",
741		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[17],
742		"mbx_completion_host_mbx_cntrl_timeout");
743
744	SYSCTL_ADD_QUAD(ctx, node_children,
745		OID_AUTO, "mbx_completion_fw_mbx_cntrl_timeout",
746		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[18],
747		"mbx_completion_fw_mbx_cntrl_timeout");
748	return;
749}
750
751static void
752qlnx_add_hw_stats_sysctls(qla_host_t *ha)
753{
754	qlnx_add_hw_mac_stats_sysctls(ha);
755	qlnx_add_hw_rcv_stats_sysctls(ha);
756	qlnx_add_hw_xmt_stats_sysctls(ha);
757	qlnx_add_hw_mbx_cmpl_stats_sysctls(ha);
758
759	return;
760}
761
762static void
763qlnx_add_drvr_sds_stats(qla_host_t *ha)
764{
765        struct sysctl_ctx_list  *ctx;
766        struct sysctl_oid_list  *children;
767        struct sysctl_oid_list  *node_children;
768        struct sysctl_oid       *ctx_oid;
769        int                     i;
770        uint8_t                 name_str[16];
771
772        ctx = device_get_sysctl_ctx(ha->pci_dev);
773        children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev));
774
775        ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats_drvr_sds",
776	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "stats_drvr_sds");
777        children = SYSCTL_CHILDREN(ctx_oid);
778
779        for (i = 0; i < ha->hw.num_sds_rings; i++) {
780                bzero(name_str, (sizeof(uint8_t) * sizeof(name_str)));
781                snprintf(name_str, sizeof(name_str), "%d", i);
782
783                ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, name_str,
784		    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, name_str);
785                node_children = SYSCTL_CHILDREN(ctx_oid);
786
787                SYSCTL_ADD_QUAD(ctx, node_children,
788			OID_AUTO, "intr_count",
789                        CTLFLAG_RD, &ha->hw.sds[i].intr_count,
790                        "intr_count");
791
792                SYSCTL_ADD_UINT(ctx, node_children,
793			OID_AUTO, "rx_free",
794                        CTLFLAG_RD, &ha->hw.sds[i].rx_free,
795			ha->hw.sds[i].rx_free, "rx_free");
796	}
797
798	return;
799}
800static void
801qlnx_add_drvr_rds_stats(qla_host_t *ha)
802{
803        struct sysctl_ctx_list  *ctx;
804        struct sysctl_oid_list  *children;
805        struct sysctl_oid_list  *node_children;
806        struct sysctl_oid       *ctx_oid;
807        int                     i;
808        uint8_t                 name_str[16];
809
810        ctx = device_get_sysctl_ctx(ha->pci_dev);
811        children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev));
812
813        ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats_drvr_rds",
814            CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "stats_drvr_rds");
815        children = SYSCTL_CHILDREN(ctx_oid);
816
817        for (i = 0; i < ha->hw.num_rds_rings; i++) {
818                bzero(name_str, (sizeof(uint8_t) * sizeof(name_str)));
819                snprintf(name_str, sizeof(name_str), "%d", i);
820
821                ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, name_str,
822                    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, name_str);
823                node_children = SYSCTL_CHILDREN(ctx_oid);
824
825                SYSCTL_ADD_QUAD(ctx, node_children,
826			OID_AUTO, "count",
827                        CTLFLAG_RD, &ha->hw.rds[i].count,
828                        "count");
829
830                SYSCTL_ADD_QUAD(ctx, node_children,
831			OID_AUTO, "lro_pkt_count",
832                        CTLFLAG_RD, &ha->hw.rds[i].lro_pkt_count,
833                        "lro_pkt_count");
834
835                SYSCTL_ADD_QUAD(ctx, node_children,
836			OID_AUTO, "lro_bytes",
837                        CTLFLAG_RD, &ha->hw.rds[i].lro_bytes,
838                        "lro_bytes");
839	}
840
841	return;
842}
843
844static void
845qlnx_add_drvr_tx_stats(qla_host_t *ha)
846{
847        struct sysctl_ctx_list  *ctx;
848        struct sysctl_oid_list  *children;
849        struct sysctl_oid_list  *node_children;
850        struct sysctl_oid       *ctx_oid;
851        int                     i;
852        uint8_t                 name_str[16];
853
854        ctx = device_get_sysctl_ctx(ha->pci_dev);
855        children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev));
856
857        ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats_drvr_xmt",
858            CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "stats_drvr_xmt");
859        children = SYSCTL_CHILDREN(ctx_oid);
860
861        for (i = 0; i < ha->hw.num_tx_rings; i++) {
862                bzero(name_str, (sizeof(uint8_t) * sizeof(name_str)));
863                snprintf(name_str, sizeof(name_str), "%d", i);
864
865                ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, name_str,
866                    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, name_str);
867                node_children = SYSCTL_CHILDREN(ctx_oid);
868
869                SYSCTL_ADD_QUAD(ctx, node_children,
870			OID_AUTO, "count",
871                        CTLFLAG_RD, &ha->tx_ring[i].count,
872                        "count");
873
874#ifdef QL_ENABLE_ISCSI_TLV
875                SYSCTL_ADD_QUAD(ctx, node_children,
876			OID_AUTO, "iscsi_pkt_count",
877                        CTLFLAG_RD, &ha->tx_ring[i].iscsi_pkt_count,
878                        "iscsi_pkt_count");
879#endif /* #ifdef QL_ENABLE_ISCSI_TLV */
880	}
881
882	return;
883}
884
885static void
886qlnx_add_drvr_stats_sysctls(qla_host_t *ha)
887{
888	qlnx_add_drvr_sds_stats(ha);
889	qlnx_add_drvr_rds_stats(ha);
890	qlnx_add_drvr_tx_stats(ha);
891	return;
892}
893
894/*
895 * Name: ql_hw_add_sysctls
896 * Function: Add P3Plus specific sysctls
897 */
898void
899ql_hw_add_sysctls(qla_host_t *ha)
900{
901        device_t	dev;
902
903        dev = ha->pci_dev;
904
905	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
906		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
907		OID_AUTO, "num_rds_rings", CTLFLAG_RD, &ha->hw.num_rds_rings,
908		ha->hw.num_rds_rings, "Number of Rcv Descriptor Rings");
909
910        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
911                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
912                OID_AUTO, "num_sds_rings", CTLFLAG_RD, &ha->hw.num_sds_rings,
913		ha->hw.num_sds_rings, "Number of Status Descriptor Rings");
914
915        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
916                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
917                OID_AUTO, "num_tx_rings", CTLFLAG_RD, &ha->hw.num_tx_rings,
918		ha->hw.num_tx_rings, "Number of Transmit Rings");
919
920        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
921                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
922                OID_AUTO, "tx_ring_index", CTLFLAG_RW, &ha->txr_idx,
923		ha->txr_idx, "Tx Ring Used");
924
925        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
926                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
927                OID_AUTO, "max_tx_segs", CTLFLAG_RD, &ha->hw.max_tx_segs,
928		ha->hw.max_tx_segs, "Max # of Segments in a non-TSO pkt");
929
930	ha->hw.sds_cidx_thres = 32;
931        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
932                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
933                OID_AUTO, "sds_cidx_thres", CTLFLAG_RW, &ha->hw.sds_cidx_thres,
934		ha->hw.sds_cidx_thres,
935		"Number of SDS entries to process before updating"
936		" SDS Ring Consumer Index");
937
938	ha->hw.rds_pidx_thres = 32;
939        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
940                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
941                OID_AUTO, "rds_pidx_thres", CTLFLAG_RW, &ha->hw.rds_pidx_thres,
942		ha->hw.rds_pidx_thres,
943		"Number of Rcv Rings Entries to post before updating"
944		" RDS Ring Producer Index");
945
946        ha->hw.rcv_intr_coalesce = (3 << 16) | 256;
947        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
948                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
949                OID_AUTO, "rcv_intr_coalesce", CTLFLAG_RW,
950                &ha->hw.rcv_intr_coalesce,
951                ha->hw.rcv_intr_coalesce,
952                "Rcv Intr Coalescing Parameters\n"
953                "\tbits 15:0 max packets\n"
954                "\tbits 31:16 max micro-seconds to wait\n"
955                "\tplease run\n"
956                "\tifconfig <if> down && ifconfig <if> up\n"
957                "\tto take effect \n");
958
959        ha->hw.xmt_intr_coalesce = (64 << 16) | 64;
960        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
961                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
962                OID_AUTO, "xmt_intr_coalesce", CTLFLAG_RW,
963                &ha->hw.xmt_intr_coalesce,
964                ha->hw.xmt_intr_coalesce,
965                "Xmt Intr Coalescing Parameters\n"
966                "\tbits 15:0 max packets\n"
967                "\tbits 31:16 max micro-seconds to wait\n"
968                "\tplease run\n"
969                "\tifconfig <if> down && ifconfig <if> up\n"
970                "\tto take effect \n");
971
972        SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
973            SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
974	    "port_cfg", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
975	    (void *)ha, 0, qla_sysctl_port_cfg, "I",
976	    "Set Port Configuration if values below "
977	    "otherwise Get Port Configuration\n"
978	    "\tBits 0-3 ; 1 = DCBX Enable; 0 = DCBX Disable\n"
979	    "\tBits 4-7 : 0 = no pause; 1 = std ; 2 = ppm \n"
980	    "\tBits 8-11: std pause cfg; 0 = xmt and rcv;"
981	    " 1 = xmt only; 2 = rcv only;\n");
982
983	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
984	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
985	    "set_cam_search_mode", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
986	    (void *)ha, 0, qla_sysctl_set_cam_search_mode, "I",
987	    "Set CAM Search Mode"
988	    "\t 1 = search mode internal\n"
989	    "\t 2 = search mode auto\n");
990
991	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
992		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
993		"get_cam_search_mode",
994		CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, (void *)ha, 0,
995		qla_sysctl_get_cam_search_mode, "I",
996		"Get CAM Search Mode"
997		"\t 1 = search mode internal\n"
998		"\t 2 = search mode auto\n");
999
1000        ha->hw.enable_9kb = 1;
1001
1002        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1003                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1004                OID_AUTO, "enable_9kb", CTLFLAG_RW, &ha->hw.enable_9kb,
1005                ha->hw.enable_9kb, "Enable 9Kbyte Buffers when MTU = 9000");
1006
1007        ha->hw.enable_hw_lro = 1;
1008
1009        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1010                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1011                OID_AUTO, "enable_hw_lro", CTLFLAG_RW, &ha->hw.enable_hw_lro,
1012                ha->hw.enable_hw_lro, "Enable Hardware LRO; Default is true \n"
1013		"\t 1 : Hardware LRO if LRO is enabled\n"
1014		"\t 0 : Software LRO if LRO is enabled\n"
1015		"\t Any change requires ifconfig down/up to take effect\n"
1016		"\t Note that LRO may be turned off/on via ifconfig\n");
1017
1018        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1019                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1020                OID_AUTO, "sp_log_index", CTLFLAG_RW, &ha->hw.sp_log_index,
1021                ha->hw.sp_log_index, "sp_log_index");
1022
1023        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1024                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1025                OID_AUTO, "sp_log_stop", CTLFLAG_RW, &ha->hw.sp_log_stop,
1026                ha->hw.sp_log_stop, "sp_log_stop");
1027
1028        ha->hw.sp_log_stop_events = 0;
1029
1030        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1031                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1032                OID_AUTO, "sp_log_stop_events", CTLFLAG_RW,
1033		&ha->hw.sp_log_stop_events,
1034                ha->hw.sp_log_stop_events, "Slow path event log is stopped"
1035		" when OR of the following events occur \n"
1036		"\t 0x01 : Heart beat Failure\n"
1037		"\t 0x02 : Temperature Failure\n"
1038		"\t 0x04 : HW Initialization Failure\n"
1039		"\t 0x08 : Interface Initialization Failure\n"
1040		"\t 0x10 : Error Recovery Failure\n");
1041
1042	ha->hw.mdump_active = 0;
1043        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1044                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1045                OID_AUTO, "minidump_active", CTLFLAG_RW, &ha->hw.mdump_active,
1046		ha->hw.mdump_active,
1047		"Minidump retrieval is Active");
1048
1049	ha->hw.mdump_done = 0;
1050        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1051                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1052                OID_AUTO, "mdump_done", CTLFLAG_RW,
1053		&ha->hw.mdump_done, ha->hw.mdump_done,
1054		"Minidump has been done and available for retrieval");
1055
1056	ha->hw.mdump_capture_mask = 0xF;
1057        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1058                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1059                OID_AUTO, "minidump_capture_mask", CTLFLAG_RW,
1060		&ha->hw.mdump_capture_mask, ha->hw.mdump_capture_mask,
1061		"Minidump capture mask");
1062#ifdef QL_DBG
1063
1064	ha->err_inject = 0;
1065        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1066                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1067                OID_AUTO, "err_inject",
1068                CTLFLAG_RW, &ha->err_inject, ha->err_inject,
1069                "Error to be injected\n"
1070                "\t\t\t 0: No Errors\n"
1071                "\t\t\t 1: rcv: rxb struct invalid\n"
1072                "\t\t\t 2: rcv: mp == NULL\n"
1073                "\t\t\t 3: lro: rxb struct invalid\n"
1074                "\t\t\t 4: lro: mp == NULL\n"
1075                "\t\t\t 5: rcv: num handles invalid\n"
1076                "\t\t\t 6: reg: indirect reg rd_wr failure\n"
1077                "\t\t\t 7: ocm: offchip memory rd_wr failure\n"
1078                "\t\t\t 8: mbx: mailbox command failure\n"
1079                "\t\t\t 9: heartbeat failure\n"
1080                "\t\t\t A: temperature failure\n"
1081		"\t\t\t 11: m_getcl or m_getjcl failure\n"
1082		"\t\t\t 13: Invalid Descriptor Count in SGL Receive\n"
1083		"\t\t\t 14: Invalid Descriptor Count in LRO Receive\n"
1084		"\t\t\t 15: peer port error recovery failure\n"
1085		"\t\t\t 16: tx_buf[next_prod_index].mbuf != NULL\n" );
1086
1087	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
1088            SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
1089	    "peg_stop", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
1090	    (void *)ha, 0, qla_sysctl_stop_pegs, "I", "Peg Stop");
1091
1092#endif /* #ifdef QL_DBG */
1093
1094        ha->hw.user_pri_nic = 0;
1095        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1096                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1097                OID_AUTO, "user_pri_nic", CTLFLAG_RW, &ha->hw.user_pri_nic,
1098                ha->hw.user_pri_nic,
1099                "VLAN Tag User Priority for Normal Ethernet Packets");
1100
1101        ha->hw.user_pri_iscsi = 4;
1102        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1103                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1104                OID_AUTO, "user_pri_iscsi", CTLFLAG_RW, &ha->hw.user_pri_iscsi,
1105                ha->hw.user_pri_iscsi,
1106                "VLAN Tag User Priority for iSCSI Packets");
1107
1108	qlnx_add_hw_stats_sysctls(ha);
1109	qlnx_add_drvr_stats_sysctls(ha);
1110
1111	return;
1112}
1113
1114void
1115ql_hw_link_status(qla_host_t *ha)
1116{
1117	device_printf(ha->pci_dev, "cable_oui\t\t 0x%08x\n", ha->hw.cable_oui);
1118
1119	if (ha->hw.link_up) {
1120		device_printf(ha->pci_dev, "link Up\n");
1121	} else {
1122		device_printf(ha->pci_dev, "link Down\n");
1123	}
1124
1125	if (ha->hw.fduplex) {
1126		device_printf(ha->pci_dev, "Full Duplex\n");
1127	} else {
1128		device_printf(ha->pci_dev, "Half Duplex\n");
1129	}
1130
1131	if (ha->hw.autoneg) {
1132		device_printf(ha->pci_dev, "Auto Negotiation Enabled\n");
1133	} else {
1134		device_printf(ha->pci_dev, "Auto Negotiation Disabled\n");
1135	}
1136
1137	switch (ha->hw.link_speed) {
1138	case 0x710:
1139		device_printf(ha->pci_dev, "link speed\t\t 10Gps\n");
1140		break;
1141
1142	case 0x3E8:
1143		device_printf(ha->pci_dev, "link speed\t\t 1Gps\n");
1144		break;
1145
1146	case 0x64:
1147		device_printf(ha->pci_dev, "link speed\t\t 100Mbps\n");
1148		break;
1149
1150	default:
1151		device_printf(ha->pci_dev, "link speed\t\t Unknown\n");
1152		break;
1153	}
1154
1155	switch (ha->hw.module_type) {
1156	case 0x01:
1157		device_printf(ha->pci_dev, "Module Type 10GBase-LRM\n");
1158		break;
1159
1160	case 0x02:
1161		device_printf(ha->pci_dev, "Module Type 10GBase-LR\n");
1162		break;
1163
1164	case 0x03:
1165		device_printf(ha->pci_dev, "Module Type 10GBase-SR\n");
1166		break;
1167
1168	case 0x04:
1169		device_printf(ha->pci_dev,
1170			"Module Type 10GE Passive Copper(Compliant)[%d m]\n",
1171			ha->hw.cable_length);
1172		break;
1173
1174	case 0x05:
1175		device_printf(ha->pci_dev, "Module Type 10GE Active"
1176			" Limiting Copper(Compliant)[%d m]\n",
1177			ha->hw.cable_length);
1178		break;
1179
1180	case 0x06:
1181		device_printf(ha->pci_dev,
1182			"Module Type 10GE Passive Copper"
1183			" (Legacy, Best Effort)[%d m]\n",
1184			ha->hw.cable_length);
1185		break;
1186
1187	case 0x07:
1188		device_printf(ha->pci_dev, "Module Type 1000Base-SX\n");
1189		break;
1190
1191	case 0x08:
1192		device_printf(ha->pci_dev, "Module Type 1000Base-LX\n");
1193		break;
1194
1195	case 0x09:
1196		device_printf(ha->pci_dev, "Module Type 1000Base-CX\n");
1197		break;
1198
1199	case 0x0A:
1200		device_printf(ha->pci_dev, "Module Type 1000Base-T\n");
1201		break;
1202
1203	case 0x0B:
1204		device_printf(ha->pci_dev, "Module Type 1GE Passive Copper"
1205			"(Legacy, Best Effort)\n");
1206		break;
1207
1208	default:
1209		device_printf(ha->pci_dev, "Unknown Module Type 0x%x\n",
1210			ha->hw.module_type);
1211		break;
1212	}
1213
1214	if (ha->hw.link_faults == 1)
1215		device_printf(ha->pci_dev, "SFP Power Fault\n");
1216}
1217
1218/*
1219 * Name: ql_free_dma
1220 * Function: Frees the DMA'able memory allocated in ql_alloc_dma()
1221 */
1222void
1223ql_free_dma(qla_host_t *ha)
1224{
1225	uint32_t i;
1226
1227        if (ha->hw.dma_buf.flags.sds_ring) {
1228		for (i = 0; i < ha->hw.num_sds_rings; i++) {
1229			ql_free_dmabuf(ha, &ha->hw.dma_buf.sds_ring[i]);
1230		}
1231        	ha->hw.dma_buf.flags.sds_ring = 0;
1232	}
1233
1234        if (ha->hw.dma_buf.flags.rds_ring) {
1235		for (i = 0; i < ha->hw.num_rds_rings; i++) {
1236			ql_free_dmabuf(ha, &ha->hw.dma_buf.rds_ring[i]);
1237		}
1238        	ha->hw.dma_buf.flags.rds_ring = 0;
1239	}
1240
1241        if (ha->hw.dma_buf.flags.tx_ring) {
1242		ql_free_dmabuf(ha, &ha->hw.dma_buf.tx_ring);
1243        	ha->hw.dma_buf.flags.tx_ring = 0;
1244	}
1245	ql_minidump_free(ha);
1246}
1247
1248/*
1249 * Name: ql_alloc_dma
1250 * Function: Allocates DMA'able memory for Tx/Rx Rings, Tx/Rx Contexts.
1251 */
1252int
1253ql_alloc_dma(qla_host_t *ha)
1254{
1255        device_t                dev;
1256	uint32_t		i, j, size, tx_ring_size;
1257	qla_hw_t		*hw;
1258	qla_hw_tx_cntxt_t	*tx_cntxt;
1259	uint8_t			*vaddr;
1260	bus_addr_t		paddr;
1261
1262        dev = ha->pci_dev;
1263
1264        QL_DPRINT2(ha, (dev, "%s: enter\n", __func__));
1265
1266	hw = &ha->hw;
1267	/*
1268	 * Allocate Transmit Ring
1269	 */
1270	tx_ring_size = (sizeof(q80_tx_cmd_t) * NUM_TX_DESCRIPTORS);
1271	size = (tx_ring_size * ha->hw.num_tx_rings);
1272
1273	hw->dma_buf.tx_ring.alignment = 8;
1274	hw->dma_buf.tx_ring.size = size + PAGE_SIZE;
1275
1276        if (ql_alloc_dmabuf(ha, &hw->dma_buf.tx_ring)) {
1277                device_printf(dev, "%s: tx ring alloc failed\n", __func__);
1278                goto ql_alloc_dma_exit;
1279        }
1280
1281	vaddr = (uint8_t *)hw->dma_buf.tx_ring.dma_b;
1282	paddr = hw->dma_buf.tx_ring.dma_addr;
1283
1284	for (i = 0; i < ha->hw.num_tx_rings; i++) {
1285		tx_cntxt = (qla_hw_tx_cntxt_t *)&hw->tx_cntxt[i];
1286
1287		tx_cntxt->tx_ring_base = (q80_tx_cmd_t *)vaddr;
1288		tx_cntxt->tx_ring_paddr = paddr;
1289
1290		vaddr += tx_ring_size;
1291		paddr += tx_ring_size;
1292	}
1293
1294	for (i = 0; i < ha->hw.num_tx_rings; i++) {
1295		tx_cntxt = (qla_hw_tx_cntxt_t *)&hw->tx_cntxt[i];
1296
1297		tx_cntxt->tx_cons = (uint32_t *)vaddr;
1298		tx_cntxt->tx_cons_paddr = paddr;
1299
1300		vaddr += sizeof (uint32_t);
1301		paddr += sizeof (uint32_t);
1302	}
1303
1304        ha->hw.dma_buf.flags.tx_ring = 1;
1305
1306	QL_DPRINT2(ha, (dev, "%s: tx_ring phys %p virt %p\n",
1307		__func__, (void *)(hw->dma_buf.tx_ring.dma_addr),
1308		hw->dma_buf.tx_ring.dma_b));
1309	/*
1310	 * Allocate Receive Descriptor Rings
1311	 */
1312
1313	for (i = 0; i < hw->num_rds_rings; i++) {
1314		hw->dma_buf.rds_ring[i].alignment = 8;
1315		hw->dma_buf.rds_ring[i].size =
1316			(sizeof(q80_recv_desc_t)) * NUM_RX_DESCRIPTORS;
1317
1318		if (ql_alloc_dmabuf(ha, &hw->dma_buf.rds_ring[i])) {
1319			device_printf(dev, "%s: rds ring[%d] alloc failed\n",
1320				__func__, i);
1321
1322			for (j = 0; j < i; j++)
1323				ql_free_dmabuf(ha, &hw->dma_buf.rds_ring[j]);
1324
1325			goto ql_alloc_dma_exit;
1326		}
1327		QL_DPRINT4(ha, (dev, "%s: rx_ring[%d] phys %p virt %p\n",
1328			__func__, i, (void *)(hw->dma_buf.rds_ring[i].dma_addr),
1329			hw->dma_buf.rds_ring[i].dma_b));
1330	}
1331
1332	hw->dma_buf.flags.rds_ring = 1;
1333
1334	/*
1335	 * Allocate Status Descriptor Rings
1336	 */
1337
1338	for (i = 0; i < hw->num_sds_rings; i++) {
1339		hw->dma_buf.sds_ring[i].alignment = 8;
1340		hw->dma_buf.sds_ring[i].size =
1341			(sizeof(q80_stat_desc_t)) * NUM_STATUS_DESCRIPTORS;
1342
1343		if (ql_alloc_dmabuf(ha, &hw->dma_buf.sds_ring[i])) {
1344			device_printf(dev, "%s: sds ring alloc failed\n",
1345				__func__);
1346
1347			for (j = 0; j < i; j++)
1348				ql_free_dmabuf(ha, &hw->dma_buf.sds_ring[j]);
1349
1350			goto ql_alloc_dma_exit;
1351		}
1352		QL_DPRINT4(ha, (dev, "%s: sds_ring[%d] phys %p virt %p\n",
1353			__func__, i,
1354			(void *)(hw->dma_buf.sds_ring[i].dma_addr),
1355			hw->dma_buf.sds_ring[i].dma_b));
1356	}
1357	for (i = 0; i < hw->num_sds_rings; i++) {
1358		hw->sds[i].sds_ring_base =
1359			(q80_stat_desc_t *)hw->dma_buf.sds_ring[i].dma_b;
1360	}
1361
1362	hw->dma_buf.flags.sds_ring = 1;
1363
1364	return 0;
1365
1366ql_alloc_dma_exit:
1367	ql_free_dma(ha);
1368	return -1;
1369}
1370
1371#define Q8_MBX_MSEC_DELAY	5000
1372
1373static int
1374qla_mbx_cmd(qla_host_t *ha, uint32_t *h_mbox, uint32_t n_hmbox,
1375	uint32_t *fw_mbox, uint32_t n_fwmbox, uint32_t no_pause)
1376{
1377	uint32_t i;
1378	uint32_t data;
1379	int ret = 0;
1380	uint64_t start_usecs;
1381	uint64_t end_usecs;
1382	uint64_t msecs_200;
1383
1384	ql_sp_log(ha, 0, 5, no_pause, h_mbox[0], h_mbox[1], h_mbox[2], h_mbox[3]);
1385
1386	if (ha->offline || ha->qla_initiate_recovery) {
1387		ql_sp_log(ha, 1, 2, ha->offline, ha->qla_initiate_recovery, 0, 0, 0);
1388		goto exit_qla_mbx_cmd;
1389	}
1390
1391	if (((ha->err_inject & 0xFFFF) == INJCT_MBX_CMD_FAILURE) &&
1392		(((ha->err_inject & ~0xFFFF) == ((h_mbox[0] & 0xFFFF) << 16))||
1393		!(ha->err_inject & ~0xFFFF))) {
1394		ret = -3;
1395		QL_INITIATE_RECOVERY(ha);
1396		goto exit_qla_mbx_cmd;
1397	}
1398
1399	start_usecs = qla_get_usec_timestamp();
1400
1401	if (no_pause)
1402		i = 1000;
1403	else
1404		i = Q8_MBX_MSEC_DELAY;
1405
1406	while (i) {
1407		if (ha->qla_initiate_recovery) {
1408			ql_sp_log(ha, 2, 1, ha->qla_initiate_recovery, 0, 0, 0, 0);
1409			return (-1);
1410		}
1411
1412		data = READ_REG32(ha, Q8_HOST_MBOX_CNTRL);
1413		if (data == 0)
1414			break;
1415		if (no_pause) {
1416			DELAY(1000);
1417		} else {
1418			qla_mdelay(__func__, 1);
1419		}
1420		i--;
1421	}
1422
1423	if (i == 0) {
1424		device_printf(ha->pci_dev, "%s: host_mbx_cntrl 0x%08x\n",
1425			__func__, data);
1426		ql_sp_log(ha, 3, 1, data, 0, 0, 0, 0);
1427		ret = -1;
1428		ha->hw.mbx_comp_msecs[(Q8_MBX_COMP_MSECS - 2)]++;
1429		QL_INITIATE_RECOVERY(ha);
1430		goto exit_qla_mbx_cmd;
1431	}
1432
1433	for (i = 0; i < n_hmbox; i++) {
1434		WRITE_REG32(ha, (Q8_HOST_MBOX0 + (i << 2)), *h_mbox);
1435		h_mbox++;
1436	}
1437
1438	WRITE_REG32(ha, Q8_HOST_MBOX_CNTRL, 0x1);
1439
1440	i = Q8_MBX_MSEC_DELAY;
1441	while (i) {
1442		if (ha->qla_initiate_recovery) {
1443			ql_sp_log(ha, 4, 1, ha->qla_initiate_recovery, 0, 0, 0, 0);
1444			return (-1);
1445		}
1446
1447		data = READ_REG32(ha, Q8_FW_MBOX_CNTRL);
1448
1449		if ((data & 0x3) == 1) {
1450			data = READ_REG32(ha, Q8_FW_MBOX0);
1451			if ((data & 0xF000) != 0x8000)
1452				break;
1453		}
1454		if (no_pause) {
1455			DELAY(1000);
1456		} else {
1457			qla_mdelay(__func__, 1);
1458		}
1459		i--;
1460	}
1461	if (i == 0) {
1462		device_printf(ha->pci_dev, "%s: fw_mbx_cntrl 0x%08x\n",
1463			__func__, data);
1464		ql_sp_log(ha, 5, 1, data, 0, 0, 0, 0);
1465		ret = -2;
1466		ha->hw.mbx_comp_msecs[(Q8_MBX_COMP_MSECS - 1)]++;
1467		QL_INITIATE_RECOVERY(ha);
1468		goto exit_qla_mbx_cmd;
1469	}
1470
1471	for (i = 0; i < n_fwmbox; i++) {
1472		if (ha->qla_initiate_recovery) {
1473			ql_sp_log(ha, 6, 1, ha->qla_initiate_recovery, 0, 0, 0, 0);
1474			return (-1);
1475		}
1476
1477		*fw_mbox++ = READ_REG32(ha, (Q8_FW_MBOX0 + (i << 2)));
1478	}
1479
1480	WRITE_REG32(ha, Q8_FW_MBOX_CNTRL, 0x0);
1481	WRITE_REG32(ha, ha->hw.mbx_intr_mask_offset, 0x0);
1482
1483	end_usecs = qla_get_usec_timestamp();
1484
1485	if (end_usecs > start_usecs) {
1486		msecs_200 = (end_usecs - start_usecs)/(1000 * 200);
1487
1488		if (msecs_200 < 15)
1489			ha->hw.mbx_comp_msecs[msecs_200]++;
1490		else if (msecs_200 < 20)
1491			ha->hw.mbx_comp_msecs[15]++;
1492		else {
1493			device_printf(ha->pci_dev, "%s: [%ld, %ld] %ld\n", __func__,
1494				start_usecs, end_usecs, msecs_200);
1495			ha->hw.mbx_comp_msecs[16]++;
1496		}
1497	}
1498	ql_sp_log(ha, 7, 5, fw_mbox[0], fw_mbox[1], fw_mbox[2], fw_mbox[3], fw_mbox[4]);
1499
1500exit_qla_mbx_cmd:
1501	return (ret);
1502}
1503
1504int
1505qla_get_nic_partition(qla_host_t *ha, uint32_t *supports_9kb,
1506	uint32_t *num_rcvq)
1507{
1508	uint32_t *mbox, err;
1509	device_t dev = ha->pci_dev;
1510
1511	bzero(ha->hw.mbox, (sizeof (uint32_t) * Q8_NUM_MBOX));
1512
1513	mbox = ha->hw.mbox;
1514
1515	mbox[0] = Q8_MBX_GET_NIC_PARTITION | (0x2 << 16) | (0x2 << 29);
1516
1517	if (qla_mbx_cmd(ha, mbox, 2, mbox, 19, 0)) {
1518		device_printf(dev, "%s: failed0\n", __func__);
1519		return (-1);
1520	}
1521	err = mbox[0] >> 25;
1522
1523	if (supports_9kb != NULL) {
1524		if (mbox[16] & 0x80) /* bit 7 of mbox 16 */
1525			*supports_9kb = 1;
1526		else
1527			*supports_9kb = 0;
1528	}
1529
1530	if (num_rcvq != NULL)
1531		*num_rcvq =  ((mbox[6] >> 16) & 0xFFFF);
1532
1533	if ((err != 1) && (err != 0)) {
1534		device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
1535		return (-1);
1536	}
1537	return 0;
1538}
1539
1540static int
1541qla_config_intr_cntxt(qla_host_t *ha, uint32_t start_idx, uint32_t num_intrs,
1542	uint32_t create)
1543{
1544	uint32_t i, err;
1545	device_t dev = ha->pci_dev;
1546	q80_config_intr_t *c_intr;
1547	q80_config_intr_rsp_t *c_intr_rsp;
1548
1549	c_intr = (q80_config_intr_t *)ha->hw.mbox;
1550	bzero(c_intr, (sizeof (q80_config_intr_t)));
1551
1552	c_intr->opcode = Q8_MBX_CONFIG_INTR;
1553
1554	c_intr->count_version = (sizeof (q80_config_intr_t) >> 2);
1555	c_intr->count_version |= Q8_MBX_CMD_VERSION;
1556
1557	c_intr->nentries = num_intrs;
1558
1559	for (i = 0; i < num_intrs; i++) {
1560		if (create) {
1561			c_intr->intr[i].cmd_type = Q8_MBX_CONFIG_INTR_CREATE;
1562			c_intr->intr[i].msix_index = start_idx + 1 + i;
1563		} else {
1564			c_intr->intr[i].cmd_type = Q8_MBX_CONFIG_INTR_DELETE;
1565			c_intr->intr[i].msix_index =
1566				ha->hw.intr_id[(start_idx + i)];
1567		}
1568
1569		c_intr->intr[i].cmd_type |= Q8_MBX_CONFIG_INTR_TYPE_MSI_X;
1570	}
1571
1572	if (qla_mbx_cmd(ha, (uint32_t *)c_intr,
1573		(sizeof (q80_config_intr_t) >> 2),
1574		ha->hw.mbox, (sizeof (q80_config_intr_rsp_t) >> 2), 0)) {
1575		device_printf(dev, "%s: %s failed0\n", __func__,
1576			(create ? "create" : "delete"));
1577		return (-1);
1578	}
1579
1580	c_intr_rsp = (q80_config_intr_rsp_t *)ha->hw.mbox;
1581
1582	err = Q8_MBX_RSP_STATUS(c_intr_rsp->regcnt_status);
1583
1584	if (err) {
1585		device_printf(dev, "%s: %s failed1 [0x%08x, %d]\n", __func__,
1586			(create ? "create" : "delete"), err, c_intr_rsp->nentries);
1587
1588		for (i = 0; i < c_intr_rsp->nentries; i++) {
1589			device_printf(dev, "%s: [%d]:[0x%x 0x%x 0x%x]\n",
1590				__func__, i,
1591				c_intr_rsp->intr[i].status,
1592				c_intr_rsp->intr[i].intr_id,
1593				c_intr_rsp->intr[i].intr_src);
1594		}
1595
1596		return (-1);
1597	}
1598
1599	for (i = 0; ((i < num_intrs) && create); i++) {
1600		if (!c_intr_rsp->intr[i].status) {
1601			ha->hw.intr_id[(start_idx + i)] =
1602				c_intr_rsp->intr[i].intr_id;
1603			ha->hw.intr_src[(start_idx + i)] =
1604				c_intr_rsp->intr[i].intr_src;
1605		}
1606	}
1607
1608	return (0);
1609}
1610
1611/*
1612 * Name: qla_config_rss
1613 * Function: Configure RSS for the context/interface.
1614 */
1615static const uint64_t rss_key[] = { 0xbeac01fa6a42b73bULL,
1616			0x8030f20c77cb2da3ULL,
1617			0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,
1618			0x255b0ec26d5a56daULL };
1619
1620static int
1621qla_config_rss(qla_host_t *ha, uint16_t cntxt_id)
1622{
1623	q80_config_rss_t	*c_rss;
1624	q80_config_rss_rsp_t	*c_rss_rsp;
1625	uint32_t		err, i;
1626	device_t		dev = ha->pci_dev;
1627
1628	c_rss = (q80_config_rss_t *)ha->hw.mbox;
1629	bzero(c_rss, (sizeof (q80_config_rss_t)));
1630
1631	c_rss->opcode = Q8_MBX_CONFIG_RSS;
1632
1633	c_rss->count_version = (sizeof (q80_config_rss_t) >> 2);
1634	c_rss->count_version |= Q8_MBX_CMD_VERSION;
1635
1636	c_rss->hash_type = (Q8_MBX_RSS_HASH_TYPE_IPV4_TCP_IP |
1637				Q8_MBX_RSS_HASH_TYPE_IPV6_TCP_IP);
1638	//c_rss->hash_type = (Q8_MBX_RSS_HASH_TYPE_IPV4_TCP |
1639	//			Q8_MBX_RSS_HASH_TYPE_IPV6_TCP);
1640
1641	c_rss->flags = Q8_MBX_RSS_FLAGS_ENABLE_RSS;
1642	c_rss->flags |= Q8_MBX_RSS_FLAGS_USE_IND_TABLE;
1643
1644	c_rss->indtbl_mask = Q8_MBX_RSS_INDTBL_MASK;
1645
1646	c_rss->indtbl_mask |= Q8_MBX_RSS_FLAGS_MULTI_RSS_VALID;
1647	c_rss->flags |= Q8_MBX_RSS_FLAGS_TYPE_CRSS;
1648
1649	c_rss->cntxt_id = cntxt_id;
1650
1651	for (i = 0; i < 5; i++) {
1652		c_rss->rss_key[i] = rss_key[i];
1653	}
1654
1655	if (qla_mbx_cmd(ha, (uint32_t *)c_rss,
1656		(sizeof (q80_config_rss_t) >> 2),
1657		ha->hw.mbox, (sizeof(q80_config_rss_rsp_t) >> 2), 0)) {
1658		device_printf(dev, "%s: failed0\n", __func__);
1659		return (-1);
1660	}
1661	c_rss_rsp = (q80_config_rss_rsp_t *)ha->hw.mbox;
1662
1663	err = Q8_MBX_RSP_STATUS(c_rss_rsp->regcnt_status);
1664
1665	if (err) {
1666		device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
1667		return (-1);
1668	}
1669	return 0;
1670}
1671
1672static int
1673qla_set_rss_ind_table(qla_host_t *ha, uint32_t start_idx, uint32_t count,
1674        uint16_t cntxt_id, uint8_t *ind_table)
1675{
1676        q80_config_rss_ind_table_t      *c_rss_ind;
1677        q80_config_rss_ind_table_rsp_t  *c_rss_ind_rsp;
1678        uint32_t                        err;
1679        device_t                        dev = ha->pci_dev;
1680
1681	if ((count > Q8_RSS_IND_TBL_SIZE) ||
1682		((start_idx + count - 1) > Q8_RSS_IND_TBL_MAX_IDX)) {
1683		device_printf(dev, "%s: illegal count [%d, %d]\n", __func__,
1684			start_idx, count);
1685		return (-1);
1686	}
1687
1688        c_rss_ind = (q80_config_rss_ind_table_t *)ha->hw.mbox;
1689        bzero(c_rss_ind, sizeof (q80_config_rss_ind_table_t));
1690
1691        c_rss_ind->opcode = Q8_MBX_CONFIG_RSS_TABLE;
1692        c_rss_ind->count_version = (sizeof (q80_config_rss_ind_table_t) >> 2);
1693        c_rss_ind->count_version |= Q8_MBX_CMD_VERSION;
1694
1695	c_rss_ind->start_idx = start_idx;
1696	c_rss_ind->end_idx = start_idx + count - 1;
1697	c_rss_ind->cntxt_id = cntxt_id;
1698	bcopy(ind_table, c_rss_ind->ind_table, count);
1699
1700	if (qla_mbx_cmd(ha, (uint32_t *)c_rss_ind,
1701		(sizeof (q80_config_rss_ind_table_t) >> 2), ha->hw.mbox,
1702		(sizeof(q80_config_rss_ind_table_rsp_t) >> 2), 0)) {
1703		device_printf(dev, "%s: failed0\n", __func__);
1704		return (-1);
1705	}
1706
1707	c_rss_ind_rsp = (q80_config_rss_ind_table_rsp_t *)ha->hw.mbox;
1708	err = Q8_MBX_RSP_STATUS(c_rss_ind_rsp->regcnt_status);
1709
1710	if (err) {
1711		device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
1712		return (-1);
1713	}
1714	return 0;
1715}
1716
1717/*
1718 * Name: qla_config_intr_coalesce
1719 * Function: Configure Interrupt Coalescing.
1720 */
1721static int
1722qla_config_intr_coalesce(qla_host_t *ha, uint16_t cntxt_id, int tenable,
1723	int rcv)
1724{
1725	q80_config_intr_coalesc_t	*intrc;
1726	q80_config_intr_coalesc_rsp_t	*intrc_rsp;
1727	uint32_t			err, i;
1728	device_t			dev = ha->pci_dev;
1729
1730	intrc = (q80_config_intr_coalesc_t *)ha->hw.mbox;
1731	bzero(intrc, (sizeof (q80_config_intr_coalesc_t)));
1732
1733	intrc->opcode = Q8_MBX_CONFIG_INTR_COALESCE;
1734	intrc->count_version = (sizeof (q80_config_intr_coalesc_t) >> 2);
1735	intrc->count_version |= Q8_MBX_CMD_VERSION;
1736
1737	if (rcv) {
1738		intrc->flags = Q8_MBX_INTRC_FLAGS_RCV;
1739		intrc->max_pkts = ha->hw.rcv_intr_coalesce & 0xFFFF;
1740		intrc->max_mswait = (ha->hw.rcv_intr_coalesce >> 16) & 0xFFFF;
1741	} else {
1742		intrc->flags = Q8_MBX_INTRC_FLAGS_XMT;
1743		intrc->max_pkts = ha->hw.xmt_intr_coalesce & 0xFFFF;
1744		intrc->max_mswait = (ha->hw.xmt_intr_coalesce >> 16) & 0xFFFF;
1745	}
1746
1747	intrc->cntxt_id = cntxt_id;
1748
1749	if (tenable) {
1750		intrc->flags |= Q8_MBX_INTRC_FLAGS_PERIODIC;
1751		intrc->timer_type = Q8_MBX_INTRC_TIMER_PERIODIC;
1752
1753		for (i = 0; i < ha->hw.num_sds_rings; i++) {
1754			intrc->sds_ring_mask |= (1 << i);
1755		}
1756		intrc->ms_timeout = 1000;
1757	}
1758
1759	if (qla_mbx_cmd(ha, (uint32_t *)intrc,
1760		(sizeof (q80_config_intr_coalesc_t) >> 2),
1761		ha->hw.mbox, (sizeof(q80_config_intr_coalesc_rsp_t) >> 2), 0)) {
1762		device_printf(dev, "%s: failed0\n", __func__);
1763		return (-1);
1764	}
1765	intrc_rsp = (q80_config_intr_coalesc_rsp_t *)ha->hw.mbox;
1766
1767	err = Q8_MBX_RSP_STATUS(intrc_rsp->regcnt_status);
1768
1769	if (err) {
1770		device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
1771		return (-1);
1772	}
1773
1774	return 0;
1775}
1776
1777/*
1778 * Name: qla_config_mac_addr
1779 * Function: binds a MAC address to the context/interface.
1780 *	Can be unicast, multicast or broadcast.
1781 */
1782static int
1783qla_config_mac_addr(qla_host_t *ha, uint8_t *mac_addr, uint32_t add_mac,
1784	uint32_t num_mac)
1785{
1786	q80_config_mac_addr_t		*cmac;
1787	q80_config_mac_addr_rsp_t	*cmac_rsp;
1788	uint32_t			err;
1789	device_t			dev = ha->pci_dev;
1790	int				i;
1791	uint8_t				*mac_cpy = mac_addr;
1792
1793	if (num_mac > Q8_MAX_MAC_ADDRS) {
1794		device_printf(dev, "%s: %s num_mac [0x%x] > Q8_MAX_MAC_ADDRS\n",
1795			__func__, (add_mac ? "Add" : "Del"), num_mac);
1796		return (-1);
1797	}
1798
1799	cmac = (q80_config_mac_addr_t *)ha->hw.mbox;
1800	bzero(cmac, (sizeof (q80_config_mac_addr_t)));
1801
1802	cmac->opcode = Q8_MBX_CONFIG_MAC_ADDR;
1803	cmac->count_version = sizeof (q80_config_mac_addr_t) >> 2;
1804	cmac->count_version |= Q8_MBX_CMD_VERSION;
1805
1806	if (add_mac)
1807		cmac->cmd = Q8_MBX_CMAC_CMD_ADD_MAC_ADDR;
1808	else
1809		cmac->cmd = Q8_MBX_CMAC_CMD_DEL_MAC_ADDR;
1810
1811	cmac->cmd |= Q8_MBX_CMAC_CMD_CAM_INGRESS;
1812
1813	cmac->nmac_entries = num_mac;
1814	cmac->cntxt_id = ha->hw.rcv_cntxt_id;
1815
1816	for (i = 0; i < num_mac; i++) {
1817		bcopy(mac_addr, cmac->mac_addr[i].addr, Q8_ETHER_ADDR_LEN);
1818		mac_addr = mac_addr + ETHER_ADDR_LEN;
1819	}
1820
1821	if (qla_mbx_cmd(ha, (uint32_t *)cmac,
1822		(sizeof (q80_config_mac_addr_t) >> 2),
1823		ha->hw.mbox, (sizeof(q80_config_mac_addr_rsp_t) >> 2), 1)) {
1824		device_printf(dev, "%s: %s failed0\n", __func__,
1825			(add_mac ? "Add" : "Del"));
1826		return (-1);
1827	}
1828	cmac_rsp = (q80_config_mac_addr_rsp_t *)ha->hw.mbox;
1829
1830	err = Q8_MBX_RSP_STATUS(cmac_rsp->regcnt_status);
1831
1832	if (err) {
1833		device_printf(dev, "%s: %s failed1 [0x%08x]\n", __func__,
1834			(add_mac ? "Add" : "Del"), err);
1835		for (i = 0; i < num_mac; i++) {
1836			device_printf(dev, "%s: %02x:%02x:%02x:%02x:%02x:%02x\n",
1837				__func__, mac_cpy[0], mac_cpy[1], mac_cpy[2],
1838				mac_cpy[3], mac_cpy[4], mac_cpy[5]);
1839			mac_cpy += ETHER_ADDR_LEN;
1840		}
1841		return (-1);
1842	}
1843
1844	return 0;
1845}
1846
1847/*
1848 * Name: qla_set_mac_rcv_mode
1849 * Function: Enable/Disable AllMulticast and Promiscous Modes.
1850 */
1851static int
1852qla_set_mac_rcv_mode(qla_host_t *ha, uint32_t mode)
1853{
1854	q80_config_mac_rcv_mode_t	*rcv_mode;
1855	uint32_t			err;
1856	q80_config_mac_rcv_mode_rsp_t	*rcv_mode_rsp;
1857	device_t			dev = ha->pci_dev;
1858
1859	rcv_mode = (q80_config_mac_rcv_mode_t *)ha->hw.mbox;
1860	bzero(rcv_mode, (sizeof (q80_config_mac_rcv_mode_t)));
1861
1862	rcv_mode->opcode = Q8_MBX_CONFIG_MAC_RX_MODE;
1863	rcv_mode->count_version = sizeof (q80_config_mac_rcv_mode_t) >> 2;
1864	rcv_mode->count_version |= Q8_MBX_CMD_VERSION;
1865
1866	rcv_mode->mode = mode;
1867
1868	rcv_mode->cntxt_id = ha->hw.rcv_cntxt_id;
1869
1870	if (qla_mbx_cmd(ha, (uint32_t *)rcv_mode,
1871		(sizeof (q80_config_mac_rcv_mode_t) >> 2),
1872		ha->hw.mbox, (sizeof(q80_config_mac_rcv_mode_rsp_t) >> 2), 1)) {
1873		device_printf(dev, "%s: failed0\n", __func__);
1874		return (-1);
1875	}
1876	rcv_mode_rsp = (q80_config_mac_rcv_mode_rsp_t *)ha->hw.mbox;
1877
1878	err = Q8_MBX_RSP_STATUS(rcv_mode_rsp->regcnt_status);
1879
1880	if (err) {
1881		device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
1882		return (-1);
1883	}
1884
1885	return 0;
1886}
1887
1888int
1889ql_set_promisc(qla_host_t *ha)
1890{
1891	int ret;
1892
1893	ha->hw.mac_rcv_mode |= Q8_MBX_MAC_RCV_PROMISC_ENABLE;
1894	ret = qla_set_mac_rcv_mode(ha, ha->hw.mac_rcv_mode);
1895	return (ret);
1896}
1897
1898void
1899qla_reset_promisc(qla_host_t *ha)
1900{
1901	ha->hw.mac_rcv_mode &= ~Q8_MBX_MAC_RCV_PROMISC_ENABLE;
1902	(void)qla_set_mac_rcv_mode(ha, ha->hw.mac_rcv_mode);
1903}
1904
1905int
1906ql_set_allmulti(qla_host_t *ha)
1907{
1908	int ret;
1909
1910	ha->hw.mac_rcv_mode |= Q8_MBX_MAC_ALL_MULTI_ENABLE;
1911	ret = qla_set_mac_rcv_mode(ha, ha->hw.mac_rcv_mode);
1912	return (ret);
1913}
1914
1915void
1916qla_reset_allmulti(qla_host_t *ha)
1917{
1918	ha->hw.mac_rcv_mode &= ~Q8_MBX_MAC_ALL_MULTI_ENABLE;
1919	(void)qla_set_mac_rcv_mode(ha, ha->hw.mac_rcv_mode);
1920}
1921
1922/*
1923 * Name: ql_set_max_mtu
1924 * Function:
1925 *	Sets the maximum transfer unit size for the specified rcv context.
1926 */
1927int
1928ql_set_max_mtu(qla_host_t *ha, uint32_t mtu, uint16_t cntxt_id)
1929{
1930	device_t		dev;
1931	q80_set_max_mtu_t	*max_mtu;
1932	q80_set_max_mtu_rsp_t	*max_mtu_rsp;
1933	uint32_t		err;
1934
1935	dev = ha->pci_dev;
1936
1937	max_mtu = (q80_set_max_mtu_t *)ha->hw.mbox;
1938	bzero(max_mtu, (sizeof (q80_set_max_mtu_t)));
1939
1940	max_mtu->opcode = Q8_MBX_SET_MAX_MTU;
1941	max_mtu->count_version = (sizeof (q80_set_max_mtu_t) >> 2);
1942	max_mtu->count_version |= Q8_MBX_CMD_VERSION;
1943
1944	max_mtu->cntxt_id = cntxt_id;
1945	max_mtu->mtu = mtu;
1946
1947        if (qla_mbx_cmd(ha, (uint32_t *)max_mtu,
1948		(sizeof (q80_set_max_mtu_t) >> 2),
1949                ha->hw.mbox, (sizeof (q80_set_max_mtu_rsp_t) >> 2), 1)) {
1950                device_printf(dev, "%s: failed\n", __func__);
1951                return -1;
1952        }
1953
1954	max_mtu_rsp = (q80_set_max_mtu_rsp_t *)ha->hw.mbox;
1955
1956        err = Q8_MBX_RSP_STATUS(max_mtu_rsp->regcnt_status);
1957
1958        if (err) {
1959                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
1960        }
1961
1962	return 0;
1963}
1964
1965static int
1966qla_link_event_req(qla_host_t *ha, uint16_t cntxt_id)
1967{
1968	device_t		dev;
1969	q80_link_event_t	*lnk;
1970	q80_link_event_rsp_t	*lnk_rsp;
1971	uint32_t		err;
1972
1973	dev = ha->pci_dev;
1974
1975	lnk = (q80_link_event_t *)ha->hw.mbox;
1976	bzero(lnk, (sizeof (q80_link_event_t)));
1977
1978	lnk->opcode = Q8_MBX_LINK_EVENT_REQ;
1979	lnk->count_version = (sizeof (q80_link_event_t) >> 2);
1980	lnk->count_version |= Q8_MBX_CMD_VERSION;
1981
1982	lnk->cntxt_id = cntxt_id;
1983	lnk->cmd = Q8_LINK_EVENT_CMD_ENABLE_ASYNC;
1984
1985        if (qla_mbx_cmd(ha, (uint32_t *)lnk, (sizeof (q80_link_event_t) >> 2),
1986                ha->hw.mbox, (sizeof (q80_link_event_rsp_t) >> 2), 0)) {
1987                device_printf(dev, "%s: failed\n", __func__);
1988                return -1;
1989        }
1990
1991	lnk_rsp = (q80_link_event_rsp_t *)ha->hw.mbox;
1992
1993        err = Q8_MBX_RSP_STATUS(lnk_rsp->regcnt_status);
1994
1995        if (err) {
1996                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
1997        }
1998
1999	return 0;
2000}
2001
2002static int
2003qla_config_fw_lro(qla_host_t *ha, uint16_t cntxt_id)
2004{
2005	device_t		dev;
2006	q80_config_fw_lro_t	*fw_lro;
2007	q80_config_fw_lro_rsp_t	*fw_lro_rsp;
2008	uint32_t		err;
2009
2010	dev = ha->pci_dev;
2011
2012	fw_lro = (q80_config_fw_lro_t *)ha->hw.mbox;
2013	bzero(fw_lro, sizeof(q80_config_fw_lro_t));
2014
2015	fw_lro->opcode = Q8_MBX_CONFIG_FW_LRO;
2016	fw_lro->count_version = (sizeof (q80_config_fw_lro_t) >> 2);
2017	fw_lro->count_version |= Q8_MBX_CMD_VERSION;
2018
2019	fw_lro->flags |= Q8_MBX_FW_LRO_IPV4 | Q8_MBX_FW_LRO_IPV4_WO_DST_IP_CHK;
2020	fw_lro->flags |= Q8_MBX_FW_LRO_IPV6 | Q8_MBX_FW_LRO_IPV6_WO_DST_IP_CHK;
2021
2022	fw_lro->cntxt_id = cntxt_id;
2023
2024	if (qla_mbx_cmd(ha, (uint32_t *)fw_lro,
2025		(sizeof (q80_config_fw_lro_t) >> 2),
2026		ha->hw.mbox, (sizeof (q80_config_fw_lro_rsp_t) >> 2), 0)) {
2027		device_printf(dev, "%s: failed\n", __func__);
2028		return -1;
2029	}
2030
2031	fw_lro_rsp = (q80_config_fw_lro_rsp_t *)ha->hw.mbox;
2032
2033	err = Q8_MBX_RSP_STATUS(fw_lro_rsp->regcnt_status);
2034
2035	if (err) {
2036		device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
2037	}
2038
2039	return 0;
2040}
2041
2042static int
2043qla_set_cam_search_mode(qla_host_t *ha, uint32_t search_mode)
2044{
2045	device_t                dev;
2046	q80_hw_config_t         *hw_config;
2047	q80_hw_config_rsp_t     *hw_config_rsp;
2048	uint32_t                err;
2049
2050	dev = ha->pci_dev;
2051
2052	hw_config = (q80_hw_config_t *)ha->hw.mbox;
2053	bzero(hw_config, sizeof (q80_hw_config_t));
2054
2055	hw_config->opcode = Q8_MBX_HW_CONFIG;
2056	hw_config->count_version = Q8_HW_CONFIG_SET_CAM_SEARCH_MODE_COUNT;
2057	hw_config->count_version |= Q8_MBX_CMD_VERSION;
2058
2059	hw_config->cmd = Q8_HW_CONFIG_SET_CAM_SEARCH_MODE;
2060
2061	hw_config->u.set_cam_search_mode.mode = search_mode;
2062
2063	if (qla_mbx_cmd(ha, (uint32_t *)hw_config,
2064		(sizeof (q80_hw_config_t) >> 2),
2065		ha->hw.mbox, (sizeof (q80_hw_config_rsp_t) >> 2), 0)) {
2066		device_printf(dev, "%s: failed\n", __func__);
2067		return -1;
2068	}
2069	hw_config_rsp = (q80_hw_config_rsp_t *)ha->hw.mbox;
2070
2071	err = Q8_MBX_RSP_STATUS(hw_config_rsp->regcnt_status);
2072
2073	if (err) {
2074		device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
2075	}
2076
2077	return 0;
2078}
2079
2080static int
2081qla_get_cam_search_mode(qla_host_t *ha)
2082{
2083	device_t                dev;
2084	q80_hw_config_t         *hw_config;
2085	q80_hw_config_rsp_t     *hw_config_rsp;
2086	uint32_t                err;
2087
2088	dev = ha->pci_dev;
2089
2090	hw_config = (q80_hw_config_t *)ha->hw.mbox;
2091	bzero(hw_config, sizeof (q80_hw_config_t));
2092
2093	hw_config->opcode = Q8_MBX_HW_CONFIG;
2094	hw_config->count_version = Q8_HW_CONFIG_GET_CAM_SEARCH_MODE_COUNT;
2095	hw_config->count_version |= Q8_MBX_CMD_VERSION;
2096
2097	hw_config->cmd = Q8_HW_CONFIG_GET_CAM_SEARCH_MODE;
2098
2099	if (qla_mbx_cmd(ha, (uint32_t *)hw_config,
2100		(sizeof (q80_hw_config_t) >> 2),
2101		ha->hw.mbox, (sizeof (q80_hw_config_rsp_t) >> 2), 0)) {
2102		device_printf(dev, "%s: failed\n", __func__);
2103		return -1;
2104	}
2105	hw_config_rsp = (q80_hw_config_rsp_t *)ha->hw.mbox;
2106
2107	err = Q8_MBX_RSP_STATUS(hw_config_rsp->regcnt_status);
2108
2109	if (err) {
2110		device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
2111	} else {
2112		device_printf(dev, "%s: cam search mode [0x%08x]\n", __func__,
2113			hw_config_rsp->u.get_cam_search_mode.mode);
2114	}
2115
2116	return 0;
2117}
2118
2119static int
2120qla_get_hw_stats(qla_host_t *ha, uint32_t cmd, uint32_t rsp_size)
2121{
2122	device_t		dev;
2123	q80_get_stats_t		*stat;
2124	q80_get_stats_rsp_t	*stat_rsp;
2125	uint32_t		err;
2126
2127	dev = ha->pci_dev;
2128
2129	stat = (q80_get_stats_t *)ha->hw.mbox;
2130	bzero(stat, (sizeof (q80_get_stats_t)));
2131
2132	stat->opcode = Q8_MBX_GET_STATS;
2133	stat->count_version = 2;
2134	stat->count_version |= Q8_MBX_CMD_VERSION;
2135
2136	stat->cmd = cmd;
2137
2138        if (qla_mbx_cmd(ha, (uint32_t *)stat, 2,
2139                ha->hw.mbox, (rsp_size >> 2), 0)) {
2140                device_printf(dev, "%s: failed\n", __func__);
2141                return -1;
2142        }
2143
2144	stat_rsp = (q80_get_stats_rsp_t *)ha->hw.mbox;
2145
2146        err = Q8_MBX_RSP_STATUS(stat_rsp->regcnt_status);
2147
2148        if (err) {
2149                return -1;
2150        }
2151
2152	return 0;
2153}
2154
2155void
2156ql_get_stats(qla_host_t *ha)
2157{
2158	q80_get_stats_rsp_t	*stat_rsp;
2159	q80_mac_stats_t		*mstat;
2160	q80_xmt_stats_t		*xstat;
2161	q80_rcv_stats_t		*rstat;
2162	uint32_t		cmd;
2163	int			i;
2164	if_t ifp = ha->ifp;
2165
2166	if (ifp == NULL)
2167		return;
2168
2169	if (QLA_LOCK(ha, __func__, QLA_LOCK_DEFAULT_MS_TIMEOUT, 0) != 0) {
2170		device_printf(ha->pci_dev, "%s: failed\n", __func__);
2171		return;
2172	}
2173
2174	if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
2175		QLA_UNLOCK(ha, __func__);
2176		return;
2177	}
2178
2179	stat_rsp = (q80_get_stats_rsp_t *)ha->hw.mbox;
2180	/*
2181	 * Get MAC Statistics
2182	 */
2183	cmd = Q8_GET_STATS_CMD_TYPE_MAC;
2184//	cmd |= Q8_GET_STATS_CMD_CLEAR;
2185
2186	cmd |= ((ha->pci_func & 0x1) << 16);
2187
2188	if (ha->qla_watchdog_pause || (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) ||
2189		ha->offline)
2190		goto ql_get_stats_exit;
2191
2192	if (qla_get_hw_stats(ha, cmd, sizeof (q80_get_stats_rsp_t)) == 0) {
2193		mstat = (q80_mac_stats_t *)&stat_rsp->u.mac;
2194		bcopy(mstat, &ha->hw.mac, sizeof(q80_mac_stats_t));
2195	} else {
2196                device_printf(ha->pci_dev, "%s: mac failed [0x%08x]\n",
2197			__func__, ha->hw.mbox[0]);
2198	}
2199	/*
2200	 * Get RCV Statistics
2201	 */
2202	cmd = Q8_GET_STATS_CMD_RCV | Q8_GET_STATS_CMD_TYPE_CNTXT;
2203//	cmd |= Q8_GET_STATS_CMD_CLEAR;
2204	cmd |= (ha->hw.rcv_cntxt_id << 16);
2205
2206	if (ha->qla_watchdog_pause || (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) ||
2207		ha->offline)
2208		goto ql_get_stats_exit;
2209
2210	if (qla_get_hw_stats(ha, cmd, sizeof (q80_get_stats_rsp_t)) == 0) {
2211		rstat = (q80_rcv_stats_t *)&stat_rsp->u.rcv;
2212		bcopy(rstat, &ha->hw.rcv, sizeof(q80_rcv_stats_t));
2213	} else {
2214                device_printf(ha->pci_dev, "%s: rcv failed [0x%08x]\n",
2215			__func__, ha->hw.mbox[0]);
2216	}
2217
2218	if (ha->qla_watchdog_pause || (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) ||
2219		ha->offline)
2220		goto ql_get_stats_exit;
2221	/*
2222	 * Get XMT Statistics
2223	 */
2224	for (i = 0 ; (i < ha->hw.num_tx_rings); i++) {
2225		if (ha->qla_watchdog_pause ||
2226			(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) ||
2227			ha->offline)
2228			goto ql_get_stats_exit;
2229
2230		cmd = Q8_GET_STATS_CMD_XMT | Q8_GET_STATS_CMD_TYPE_CNTXT;
2231//		cmd |= Q8_GET_STATS_CMD_CLEAR;
2232		cmd |= (ha->hw.tx_cntxt[i].tx_cntxt_id << 16);
2233
2234		if (qla_get_hw_stats(ha, cmd, sizeof(q80_get_stats_rsp_t))
2235			== 0) {
2236			xstat = (q80_xmt_stats_t *)&stat_rsp->u.xmt;
2237			bcopy(xstat, &ha->hw.xmt[i], sizeof(q80_xmt_stats_t));
2238		} else {
2239			device_printf(ha->pci_dev, "%s: xmt failed [0x%08x]\n",
2240				__func__, ha->hw.mbox[0]);
2241		}
2242	}
2243
2244ql_get_stats_exit:
2245	QLA_UNLOCK(ha, __func__);
2246
2247	return;
2248}
2249
2250/*
2251 * Name: qla_tx_tso
2252 * Function: Checks if the packet to be transmitted is a candidate for
2253 *	Large TCP Segment Offload. If yes, the appropriate fields in the Tx
2254 *	Ring Structure are plugged in.
2255 */
2256static int
2257qla_tx_tso(qla_host_t *ha, struct mbuf *mp, q80_tx_cmd_t *tx_cmd, uint8_t *hdr)
2258{
2259	struct ether_vlan_header *eh;
2260	struct ip *ip = NULL;
2261	struct ip6_hdr *ip6 = NULL;
2262	struct tcphdr *th = NULL;
2263	uint32_t ehdrlen,  hdrlen, ip_hlen, tcp_hlen, tcp_opt_off;
2264	uint16_t etype, opcode, offload = 1;
2265
2266	eh = mtod(mp, struct ether_vlan_header *);
2267
2268	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
2269		ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
2270		etype = ntohs(eh->evl_proto);
2271	} else {
2272		ehdrlen = ETHER_HDR_LEN;
2273		etype = ntohs(eh->evl_encap_proto);
2274	}
2275
2276	hdrlen = 0;
2277
2278	switch (etype) {
2279		case ETHERTYPE_IP:
2280
2281			tcp_opt_off = ehdrlen + sizeof(struct ip) +
2282					sizeof(struct tcphdr);
2283
2284			if (mp->m_len < tcp_opt_off) {
2285				m_copydata(mp, 0, tcp_opt_off, hdr);
2286				ip = (struct ip *)(hdr + ehdrlen);
2287			} else {
2288				ip = (struct ip *)(mp->m_data + ehdrlen);
2289			}
2290
2291			ip_hlen = ip->ip_hl << 2;
2292			opcode = Q8_TX_CMD_OP_XMT_TCP_LSO;
2293
2294
2295			if ((ip->ip_p != IPPROTO_TCP) ||
2296				(ip_hlen != sizeof (struct ip))){
2297				/* IP Options are not supported */
2298
2299				offload = 0;
2300			} else
2301				th = (struct tcphdr *)((caddr_t)ip + ip_hlen);
2302
2303		break;
2304
2305		case ETHERTYPE_IPV6:
2306
2307			tcp_opt_off = ehdrlen + sizeof(struct ip6_hdr) +
2308					sizeof (struct tcphdr);
2309
2310			if (mp->m_len < tcp_opt_off) {
2311				m_copydata(mp, 0, tcp_opt_off, hdr);
2312				ip6 = (struct ip6_hdr *)(hdr + ehdrlen);
2313			} else {
2314				ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen);
2315			}
2316
2317			ip_hlen = sizeof(struct ip6_hdr);
2318			opcode = Q8_TX_CMD_OP_XMT_TCP_LSO_IPV6;
2319
2320			if (ip6->ip6_nxt != IPPROTO_TCP) {
2321				//device_printf(dev, "%s: ipv6\n", __func__);
2322				offload = 0;
2323			} else
2324				th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen);
2325		break;
2326
2327		default:
2328			QL_DPRINT8(ha, (ha->pci_dev, "%s: type!=ip\n", __func__));
2329			offload = 0;
2330		break;
2331	}
2332
2333	if (!offload)
2334		return (-1);
2335
2336	tcp_hlen = th->th_off << 2;
2337	hdrlen = ehdrlen + ip_hlen + tcp_hlen;
2338
2339        if (mp->m_len < hdrlen) {
2340                if (mp->m_len < tcp_opt_off) {
2341                        if (tcp_hlen > sizeof(struct tcphdr)) {
2342                                m_copydata(mp, tcp_opt_off,
2343                                        (tcp_hlen - sizeof(struct tcphdr)),
2344                                        &hdr[tcp_opt_off]);
2345                        }
2346                } else {
2347                        m_copydata(mp, 0, hdrlen, hdr);
2348                }
2349        }
2350
2351	tx_cmd->mss = mp->m_pkthdr.tso_segsz;
2352
2353	tx_cmd->flags_opcode = opcode ;
2354	tx_cmd->tcp_hdr_off = ip_hlen + ehdrlen;
2355	tx_cmd->total_hdr_len = hdrlen;
2356
2357	/* Check for Multicast least significant bit of MSB == 1 */
2358	if (eh->evl_dhost[0] & 0x01) {
2359		tx_cmd->flags_opcode |= Q8_TX_CMD_FLAGS_MULTICAST;
2360	}
2361
2362	if (mp->m_len < hdrlen) {
2363		printf("%d\n", hdrlen);
2364		return (1);
2365	}
2366
2367	return (0);
2368}
2369
2370/*
2371 * Name: qla_tx_chksum
2372 * Function: Checks if the packet to be transmitted is a candidate for
2373 *	TCP/UDP Checksum offload. If yes, the appropriate fields in the Tx
2374 *	Ring Structure are plugged in.
2375 */
2376static int
2377qla_tx_chksum(qla_host_t *ha, struct mbuf *mp, uint32_t *op_code,
2378	uint32_t *tcp_hdr_off)
2379{
2380	struct ether_vlan_header *eh;
2381	struct ip *ip;
2382	struct ip6_hdr *ip6;
2383	uint32_t ehdrlen, ip_hlen;
2384	uint16_t etype, opcode, offload = 1;
2385	uint8_t buf[sizeof(struct ip6_hdr)];
2386
2387	*op_code = 0;
2388
2389	if ((mp->m_pkthdr.csum_flags &
2390		(CSUM_TCP|CSUM_UDP|CSUM_TCP_IPV6 | CSUM_UDP_IPV6)) == 0)
2391		return (-1);
2392
2393	eh = mtod(mp, struct ether_vlan_header *);
2394
2395	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
2396		ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
2397		etype = ntohs(eh->evl_proto);
2398	} else {
2399		ehdrlen = ETHER_HDR_LEN;
2400		etype = ntohs(eh->evl_encap_proto);
2401	}
2402
2403
2404	switch (etype) {
2405		case ETHERTYPE_IP:
2406			ip = (struct ip *)(mp->m_data + ehdrlen);
2407
2408			ip_hlen = sizeof (struct ip);
2409
2410			if (mp->m_len < (ehdrlen + ip_hlen)) {
2411				m_copydata(mp, ehdrlen, sizeof(struct ip), buf);
2412				ip = (struct ip *)buf;
2413			}
2414
2415			if (ip->ip_p == IPPROTO_TCP)
2416				opcode = Q8_TX_CMD_OP_XMT_TCP_CHKSUM;
2417			else if (ip->ip_p == IPPROTO_UDP)
2418				opcode = Q8_TX_CMD_OP_XMT_UDP_CHKSUM;
2419			else {
2420				//device_printf(dev, "%s: ipv4\n", __func__);
2421				offload = 0;
2422			}
2423		break;
2424
2425		case ETHERTYPE_IPV6:
2426			ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen);
2427
2428			ip_hlen = sizeof(struct ip6_hdr);
2429
2430			if (mp->m_len < (ehdrlen + ip_hlen)) {
2431				m_copydata(mp, ehdrlen, sizeof (struct ip6_hdr),
2432					buf);
2433				ip6 = (struct ip6_hdr *)buf;
2434			}
2435
2436			if (ip6->ip6_nxt == IPPROTO_TCP)
2437				opcode = Q8_TX_CMD_OP_XMT_TCP_CHKSUM_IPV6;
2438			else if (ip6->ip6_nxt == IPPROTO_UDP)
2439				opcode = Q8_TX_CMD_OP_XMT_UDP_CHKSUM_IPV6;
2440			else {
2441				//device_printf(dev, "%s: ipv6\n", __func__);
2442				offload = 0;
2443			}
2444		break;
2445
2446		default:
2447			offload = 0;
2448		break;
2449	}
2450	if (!offload)
2451		return (-1);
2452
2453	*op_code = opcode;
2454	*tcp_hdr_off = (ip_hlen + ehdrlen);
2455
2456	return (0);
2457}
2458
2459#define QLA_TX_MIN_FREE 2
2460/*
2461 * Name: ql_hw_send
2462 * Function: Transmits a packet. It first checks if the packet is a
2463 *	candidate for Large TCP Segment Offload and then for UDP/TCP checksum
2464 *	offload. If either of these creteria are not met, it is transmitted
2465 *	as a regular ethernet frame.
2466 */
2467int
2468ql_hw_send(qla_host_t *ha, bus_dma_segment_t *segs, int nsegs,
2469	uint32_t tx_idx, struct mbuf *mp, uint32_t txr_idx, uint32_t iscsi_pdu)
2470{
2471	struct ether_vlan_header *eh;
2472	qla_hw_t *hw = &ha->hw;
2473	q80_tx_cmd_t *tx_cmd, tso_cmd;
2474	bus_dma_segment_t *c_seg;
2475	uint32_t num_tx_cmds, hdr_len = 0;
2476	uint32_t total_length = 0, bytes, tx_cmd_count = 0, txr_next;
2477	device_t dev;
2478	int i, ret;
2479	uint8_t *src = NULL, *dst = NULL;
2480	uint8_t frame_hdr[QL_FRAME_HDR_SIZE];
2481	uint32_t op_code = 0;
2482	uint32_t tcp_hdr_off = 0;
2483
2484	dev = ha->pci_dev;
2485
2486	/*
2487	 * Always make sure there is atleast one empty slot in the tx_ring
2488	 * tx_ring is considered full when there only one entry available
2489	 */
2490        num_tx_cmds = (nsegs + (Q8_TX_CMD_MAX_SEGMENTS - 1)) >> 2;
2491
2492	total_length = mp->m_pkthdr.len;
2493	if (total_length > QLA_MAX_TSO_FRAME_SIZE) {
2494		device_printf(dev, "%s: total length exceeds maxlen(%d)\n",
2495			__func__, total_length);
2496		return (EINVAL);
2497	}
2498	eh = mtod(mp, struct ether_vlan_header *);
2499
2500	if (mp->m_pkthdr.csum_flags & CSUM_TSO) {
2501		bzero((void *)&tso_cmd, sizeof(q80_tx_cmd_t));
2502
2503		src = frame_hdr;
2504		ret = qla_tx_tso(ha, mp, &tso_cmd, src);
2505
2506		if (!(ret & ~1)) {
2507			/* find the additional tx_cmd descriptors required */
2508
2509			if (mp->m_flags & M_VLANTAG)
2510				tso_cmd.total_hdr_len += ETHER_VLAN_ENCAP_LEN;
2511
2512			hdr_len = tso_cmd.total_hdr_len;
2513
2514			bytes = sizeof(q80_tx_cmd_t) - Q8_TX_CMD_TSO_ALIGN;
2515			bytes = QL_MIN(bytes, hdr_len);
2516
2517			num_tx_cmds++;
2518			hdr_len -= bytes;
2519
2520			while (hdr_len) {
2521				bytes = QL_MIN((sizeof(q80_tx_cmd_t)), hdr_len);
2522				hdr_len -= bytes;
2523				num_tx_cmds++;
2524			}
2525			hdr_len = tso_cmd.total_hdr_len;
2526
2527			if (ret == 0)
2528				src = (uint8_t *)eh;
2529		} else
2530			return (EINVAL);
2531	} else {
2532		(void)qla_tx_chksum(ha, mp, &op_code, &tcp_hdr_off);
2533	}
2534
2535	if (hw->tx_cntxt[txr_idx].txr_free <= (num_tx_cmds + QLA_TX_MIN_FREE)) {
2536		ql_hw_tx_done_locked(ha, txr_idx);
2537		if (hw->tx_cntxt[txr_idx].txr_free <=
2538				(num_tx_cmds + QLA_TX_MIN_FREE)) {
2539        		QL_DPRINT8(ha, (dev, "%s: (hw->txr_free <= "
2540				"(num_tx_cmds + QLA_TX_MIN_FREE))\n",
2541				__func__));
2542			return (-1);
2543		}
2544	}
2545
2546	for (i = 0; i < num_tx_cmds; i++) {
2547		int j;
2548
2549		j = (tx_idx+i) & (NUM_TX_DESCRIPTORS - 1);
2550
2551		if (NULL != ha->tx_ring[txr_idx].tx_buf[j].m_head) {
2552			QL_ASSERT(ha, 0, \
2553				("%s [%d]: txr_idx = %d tx_idx = %d mbuf = %p\n",\
2554				__func__, __LINE__, txr_idx, j,\
2555				ha->tx_ring[txr_idx].tx_buf[j].m_head));
2556			return (EINVAL);
2557		}
2558	}
2559
2560	tx_cmd = &hw->tx_cntxt[txr_idx].tx_ring_base[tx_idx];
2561
2562        if (!(mp->m_pkthdr.csum_flags & CSUM_TSO)) {
2563                if (nsegs > ha->hw.max_tx_segs)
2564                        ha->hw.max_tx_segs = nsegs;
2565
2566                bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t));
2567
2568                if (op_code) {
2569                        tx_cmd->flags_opcode = op_code;
2570                        tx_cmd->tcp_hdr_off = tcp_hdr_off;
2571
2572                } else {
2573                        tx_cmd->flags_opcode = Q8_TX_CMD_OP_XMT_ETHER;
2574                }
2575	} else {
2576		bcopy(&tso_cmd, tx_cmd, sizeof(q80_tx_cmd_t));
2577		ha->tx_tso_frames++;
2578	}
2579
2580	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
2581        	tx_cmd->flags_opcode |= Q8_TX_CMD_FLAGS_VLAN_TAGGED;
2582
2583		if (iscsi_pdu)
2584			eh->evl_tag |= ha->hw.user_pri_iscsi << 13;
2585
2586	} else if (mp->m_flags & M_VLANTAG) {
2587		if (hdr_len) { /* TSO */
2588			tx_cmd->flags_opcode |= (Q8_TX_CMD_FLAGS_VLAN_TAGGED |
2589						Q8_TX_CMD_FLAGS_HW_VLAN_ID);
2590			tx_cmd->tcp_hdr_off += ETHER_VLAN_ENCAP_LEN;
2591		} else
2592			tx_cmd->flags_opcode |= Q8_TX_CMD_FLAGS_HW_VLAN_ID;
2593
2594		ha->hw_vlan_tx_frames++;
2595		tx_cmd->vlan_tci = mp->m_pkthdr.ether_vtag;
2596
2597		if (iscsi_pdu) {
2598			tx_cmd->vlan_tci |= ha->hw.user_pri_iscsi << 13;
2599			mp->m_pkthdr.ether_vtag = tx_cmd->vlan_tci;
2600		}
2601	}
2602
2603        tx_cmd->n_bufs = (uint8_t)nsegs;
2604        tx_cmd->data_len_lo = (uint8_t)(total_length & 0xFF);
2605        tx_cmd->data_len_hi = qla_host_to_le16(((uint16_t)(total_length >> 8)));
2606	tx_cmd->cntxtid = Q8_TX_CMD_PORT_CNXTID(ha->pci_func);
2607
2608	c_seg = segs;
2609
2610	while (1) {
2611		for (i = 0; ((i < Q8_TX_CMD_MAX_SEGMENTS) && nsegs); i++) {
2612			switch (i) {
2613			case 0:
2614				tx_cmd->buf1_addr = c_seg->ds_addr;
2615				tx_cmd->buf1_len = c_seg->ds_len;
2616				break;
2617
2618			case 1:
2619				tx_cmd->buf2_addr = c_seg->ds_addr;
2620				tx_cmd->buf2_len = c_seg->ds_len;
2621				break;
2622
2623			case 2:
2624				tx_cmd->buf3_addr = c_seg->ds_addr;
2625				tx_cmd->buf3_len = c_seg->ds_len;
2626				break;
2627
2628			case 3:
2629				tx_cmd->buf4_addr = c_seg->ds_addr;
2630				tx_cmd->buf4_len = c_seg->ds_len;
2631				break;
2632			}
2633
2634			c_seg++;
2635			nsegs--;
2636		}
2637
2638		txr_next = hw->tx_cntxt[txr_idx].txr_next =
2639			(hw->tx_cntxt[txr_idx].txr_next + 1) &
2640				(NUM_TX_DESCRIPTORS - 1);
2641		tx_cmd_count++;
2642
2643		if (!nsegs)
2644			break;
2645
2646		tx_cmd = &hw->tx_cntxt[txr_idx].tx_ring_base[txr_next];
2647		bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t));
2648	}
2649
2650	if (mp->m_pkthdr.csum_flags & CSUM_TSO) {
2651		/* TSO : Copy the header in the following tx cmd descriptors */
2652
2653		txr_next = hw->tx_cntxt[txr_idx].txr_next;
2654
2655		tx_cmd = &hw->tx_cntxt[txr_idx].tx_ring_base[txr_next];
2656		bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t));
2657
2658		bytes = sizeof(q80_tx_cmd_t) - Q8_TX_CMD_TSO_ALIGN;
2659		bytes = QL_MIN(bytes, hdr_len);
2660
2661		dst = (uint8_t *)tx_cmd + Q8_TX_CMD_TSO_ALIGN;
2662
2663		if (mp->m_flags & M_VLANTAG) {
2664			/* first copy the src/dst MAC addresses */
2665			bcopy(src, dst, (ETHER_ADDR_LEN * 2));
2666			dst += (ETHER_ADDR_LEN * 2);
2667			src += (ETHER_ADDR_LEN * 2);
2668
2669			*((uint16_t *)dst) = htons(ETHERTYPE_VLAN);
2670			dst += 2;
2671			*((uint16_t *)dst) = htons(mp->m_pkthdr.ether_vtag);
2672			dst += 2;
2673
2674			/* bytes left in src header */
2675			hdr_len -= ((ETHER_ADDR_LEN * 2) +
2676					ETHER_VLAN_ENCAP_LEN);
2677
2678			/* bytes left in TxCmd Entry */
2679			bytes -= ((ETHER_ADDR_LEN * 2) + ETHER_VLAN_ENCAP_LEN);
2680
2681			bcopy(src, dst, bytes);
2682			src += bytes;
2683			hdr_len -= bytes;
2684		} else {
2685			bcopy(src, dst, bytes);
2686			src += bytes;
2687			hdr_len -= bytes;
2688		}
2689
2690		txr_next = hw->tx_cntxt[txr_idx].txr_next =
2691				(hw->tx_cntxt[txr_idx].txr_next + 1) &
2692					(NUM_TX_DESCRIPTORS - 1);
2693		tx_cmd_count++;
2694
2695		while (hdr_len) {
2696			tx_cmd = &hw->tx_cntxt[txr_idx].tx_ring_base[txr_next];
2697			bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t));
2698
2699			bytes = QL_MIN((sizeof(q80_tx_cmd_t)), hdr_len);
2700
2701			bcopy(src, tx_cmd, bytes);
2702			src += bytes;
2703			hdr_len -= bytes;
2704
2705			txr_next = hw->tx_cntxt[txr_idx].txr_next =
2706				(hw->tx_cntxt[txr_idx].txr_next + 1) &
2707					(NUM_TX_DESCRIPTORS - 1);
2708			tx_cmd_count++;
2709		}
2710	}
2711
2712	hw->tx_cntxt[txr_idx].txr_free =
2713		hw->tx_cntxt[txr_idx].txr_free - tx_cmd_count;
2714
2715	QL_UPDATE_TX_PRODUCER_INDEX(ha, hw->tx_cntxt[txr_idx].txr_next,\
2716		txr_idx);
2717       	QL_DPRINT8(ha, (dev, "%s: return\n", __func__));
2718
2719	return (0);
2720}
2721
2722#define Q8_CONFIG_IND_TBL_SIZE	32 /* < Q8_RSS_IND_TBL_SIZE and power of 2 */
2723static int
2724qla_config_rss_ind_table(qla_host_t *ha)
2725{
2726	uint32_t i, count;
2727	uint8_t rss_ind_tbl[Q8_CONFIG_IND_TBL_SIZE];
2728
2729	for (i = 0; i < Q8_CONFIG_IND_TBL_SIZE; i++) {
2730		rss_ind_tbl[i] = i % ha->hw.num_sds_rings;
2731	}
2732
2733	for (i = 0; i <= Q8_RSS_IND_TBL_MAX_IDX ;
2734		i = i + Q8_CONFIG_IND_TBL_SIZE) {
2735		if ((i + Q8_CONFIG_IND_TBL_SIZE) > Q8_RSS_IND_TBL_MAX_IDX) {
2736			count = Q8_RSS_IND_TBL_MAX_IDX - i + 1;
2737		} else {
2738			count = Q8_CONFIG_IND_TBL_SIZE;
2739		}
2740
2741		if (qla_set_rss_ind_table(ha, i, count, ha->hw.rcv_cntxt_id,
2742			rss_ind_tbl))
2743			return (-1);
2744	}
2745
2746	return (0);
2747}
2748
2749static int
2750qla_config_soft_lro(qla_host_t *ha)
2751{
2752#if defined(INET) || defined(INET6)
2753        int i;
2754        qla_hw_t *hw = &ha->hw;
2755        struct lro_ctrl *lro;
2756
2757        for (i = 0; i < hw->num_sds_rings; i++) {
2758                lro = &hw->sds[i].lro;
2759
2760		bzero(lro, sizeof(struct lro_ctrl));
2761
2762                if (tcp_lro_init_args(lro, ha->ifp, 0, NUM_RX_DESCRIPTORS)) {
2763                        device_printf(ha->pci_dev,
2764				"%s: tcp_lro_init_args [%d] failed\n",
2765                                __func__, i);
2766                        return (-1);
2767                }
2768
2769                lro->ifp = ha->ifp;
2770        }
2771
2772        QL_DPRINT2(ha, (ha->pci_dev, "%s: LRO initialized\n", __func__));
2773#endif
2774        return (0);
2775}
2776
2777static void
2778qla_drain_soft_lro(qla_host_t *ha)
2779{
2780#if defined(INET) || defined(INET6)
2781        int i;
2782        qla_hw_t *hw = &ha->hw;
2783        struct lro_ctrl *lro;
2784
2785       	for (i = 0; i < hw->num_sds_rings; i++) {
2786               	lro = &hw->sds[i].lro;
2787
2788		tcp_lro_flush_all(lro);
2789	}
2790#endif
2791
2792	return;
2793}
2794
2795static void
2796qla_free_soft_lro(qla_host_t *ha)
2797{
2798#if defined(INET) || defined(INET6)
2799        int i;
2800        qla_hw_t *hw = &ha->hw;
2801        struct lro_ctrl *lro;
2802
2803        for (i = 0; i < hw->num_sds_rings; i++) {
2804               	lro = &hw->sds[i].lro;
2805		tcp_lro_free(lro);
2806	}
2807#endif
2808
2809	return;
2810}
2811
2812/*
2813 * Name: ql_del_hw_if
2814 * Function: Destroys the hardware specific entities corresponding to an
2815 *	Ethernet Interface
2816 */
2817void
2818ql_del_hw_if(qla_host_t *ha)
2819{
2820	uint32_t i;
2821	uint32_t num_msix;
2822
2823	(void)qla_stop_nic_func(ha);
2824
2825	qla_del_rcv_cntxt(ha);
2826
2827	if(qla_del_xmt_cntxt(ha))
2828		goto ql_del_hw_if_exit;
2829
2830	if (ha->hw.flags.init_intr_cnxt) {
2831		for (i = 0; i < ha->hw.num_sds_rings; ) {
2832			if ((i + Q8_MAX_INTR_VECTORS) < ha->hw.num_sds_rings)
2833				num_msix = Q8_MAX_INTR_VECTORS;
2834			else
2835				num_msix = ha->hw.num_sds_rings - i;
2836
2837			if (qla_config_intr_cntxt(ha, i, num_msix, 0))
2838				break;
2839
2840			i += num_msix;
2841		}
2842
2843		ha->hw.flags.init_intr_cnxt = 0;
2844	}
2845
2846ql_del_hw_if_exit:
2847	if (ha->hw.enable_soft_lro) {
2848		qla_drain_soft_lro(ha);
2849		qla_free_soft_lro(ha);
2850	}
2851
2852	return;
2853}
2854
2855void
2856qla_confirm_9kb_enable(qla_host_t *ha)
2857{
2858//	uint32_t supports_9kb = 0;
2859
2860	ha->hw.mbx_intr_mask_offset = READ_REG32(ha, Q8_MBOX_INT_MASK_MSIX);
2861
2862	/* Use MSI-X vector 0; Enable Firmware Mailbox Interrupt */
2863	WRITE_REG32(ha, Q8_MBOX_INT_ENABLE, BIT_2);
2864	WRITE_REG32(ha, ha->hw.mbx_intr_mask_offset, 0x0);
2865
2866#if 0
2867	qla_get_nic_partition(ha, &supports_9kb, NULL);
2868
2869	if (!supports_9kb)
2870#endif
2871	ha->hw.enable_9kb = 0;
2872
2873	return;
2874}
2875
2876/*
2877 * Name: ql_init_hw_if
2878 * Function: Creates the hardware specific entities corresponding to an
2879 *	Ethernet Interface - Transmit and Receive Contexts. Sets the MAC Address
2880 *	corresponding to the interface. Enables LRO if allowed.
2881 */
2882int
2883ql_init_hw_if(qla_host_t *ha)
2884{
2885	uint32_t	i;
2886	uint8_t		bcast_mac[6];
2887	qla_rdesc_t	*rdesc;
2888	uint32_t	num_msix;
2889
2890	for (i = 0; i < ha->hw.num_sds_rings; i++) {
2891		bzero(ha->hw.dma_buf.sds_ring[i].dma_b,
2892			ha->hw.dma_buf.sds_ring[i].size);
2893	}
2894
2895	for (i = 0; i < ha->hw.num_sds_rings; ) {
2896		if ((i + Q8_MAX_INTR_VECTORS) < ha->hw.num_sds_rings)
2897			num_msix = Q8_MAX_INTR_VECTORS;
2898		else
2899			num_msix = ha->hw.num_sds_rings - i;
2900
2901		if (qla_config_intr_cntxt(ha, i, num_msix, 1)) {
2902			if (i > 0) {
2903				num_msix = i;
2904
2905				for (i = 0; i < num_msix; ) {
2906					qla_config_intr_cntxt(ha, i,
2907						Q8_MAX_INTR_VECTORS, 0);
2908					i += Q8_MAX_INTR_VECTORS;
2909				}
2910			}
2911			return (-1);
2912		}
2913
2914		i = i + num_msix;
2915	}
2916
2917        ha->hw.flags.init_intr_cnxt = 1;
2918
2919	/*
2920	 * Create Receive Context
2921	 */
2922	if (qla_init_rcv_cntxt(ha)) {
2923		return (-1);
2924	}
2925
2926	for (i = 0; i < ha->hw.num_rds_rings; i++) {
2927		rdesc = &ha->hw.rds[i];
2928		rdesc->rx_next = NUM_RX_DESCRIPTORS - 2;
2929		rdesc->rx_in = 0;
2930		/* Update the RDS Producer Indices */
2931		QL_UPDATE_RDS_PRODUCER_INDEX(ha, rdesc->prod_std,\
2932			rdesc->rx_next);
2933	}
2934
2935	/*
2936	 * Create Transmit Context
2937	 */
2938	if (qla_init_xmt_cntxt(ha)) {
2939		qla_del_rcv_cntxt(ha);
2940		return (-1);
2941	}
2942	ha->hw.max_tx_segs = 0;
2943
2944	if (qla_config_mac_addr(ha, ha->hw.mac_addr, 1, 1))
2945		return(-1);
2946
2947	ha->hw.flags.unicast_mac = 1;
2948
2949	bcast_mac[0] = 0xFF; bcast_mac[1] = 0xFF; bcast_mac[2] = 0xFF;
2950	bcast_mac[3] = 0xFF; bcast_mac[4] = 0xFF; bcast_mac[5] = 0xFF;
2951
2952	if (qla_config_mac_addr(ha, bcast_mac, 1, 1))
2953		return (-1);
2954
2955	ha->hw.flags.bcast_mac = 1;
2956
2957	/*
2958	 * program any cached multicast addresses
2959	 */
2960	if (qla_hw_add_all_mcast(ha))
2961		return (-1);
2962
2963	if (ql_set_max_mtu(ha, ha->max_frame_size, ha->hw.rcv_cntxt_id))
2964		return (-1);
2965
2966	if (qla_config_rss(ha, ha->hw.rcv_cntxt_id))
2967		return (-1);
2968
2969	if (qla_config_rss_ind_table(ha))
2970		return (-1);
2971
2972	if (qla_config_intr_coalesce(ha, ha->hw.rcv_cntxt_id, 0, 1))
2973		return (-1);
2974
2975	if (qla_link_event_req(ha, ha->hw.rcv_cntxt_id))
2976		return (-1);
2977
2978	if (if_getcapenable(ha->ifp) & IFCAP_LRO) {
2979		if (ha->hw.enable_hw_lro) {
2980			ha->hw.enable_soft_lro = 0;
2981
2982			if (qla_config_fw_lro(ha, ha->hw.rcv_cntxt_id))
2983				return (-1);
2984		} else {
2985			ha->hw.enable_soft_lro = 1;
2986
2987			if (qla_config_soft_lro(ha))
2988				return (-1);
2989		}
2990	}
2991
2992        if (qla_init_nic_func(ha))
2993                return (-1);
2994
2995        if (qla_query_fw_dcbx_caps(ha))
2996                return (-1);
2997
2998	for (i = 0; i < ha->hw.num_sds_rings; i++)
2999		QL_ENABLE_INTERRUPTS(ha, i);
3000
3001	return (0);
3002}
3003
3004static int
3005qla_map_sds_to_rds(qla_host_t *ha, uint32_t start_idx, uint32_t num_idx)
3006{
3007        device_t                dev = ha->pci_dev;
3008        q80_rq_map_sds_to_rds_t *map_rings;
3009	q80_rsp_map_sds_to_rds_t *map_rings_rsp;
3010        uint32_t                i, err;
3011        qla_hw_t                *hw = &ha->hw;
3012
3013        map_rings = (q80_rq_map_sds_to_rds_t *)ha->hw.mbox;
3014        bzero(map_rings, sizeof(q80_rq_map_sds_to_rds_t));
3015
3016        map_rings->opcode = Q8_MBX_MAP_SDS_TO_RDS;
3017        map_rings->count_version = (sizeof (q80_rq_map_sds_to_rds_t) >> 2);
3018        map_rings->count_version |= Q8_MBX_CMD_VERSION;
3019
3020        map_rings->cntxt_id = hw->rcv_cntxt_id;
3021        map_rings->num_rings = num_idx;
3022
3023	for (i = 0; i < num_idx; i++) {
3024		map_rings->sds_rds[i].sds_ring = i + start_idx;
3025		map_rings->sds_rds[i].rds_ring = i + start_idx;
3026	}
3027
3028        if (qla_mbx_cmd(ha, (uint32_t *)map_rings,
3029                (sizeof (q80_rq_map_sds_to_rds_t) >> 2),
3030                ha->hw.mbox, (sizeof(q80_rsp_add_rcv_rings_t) >> 2), 0)) {
3031                device_printf(dev, "%s: failed0\n", __func__);
3032                return (-1);
3033        }
3034
3035        map_rings_rsp = (q80_rsp_map_sds_to_rds_t *)ha->hw.mbox;
3036
3037        err = Q8_MBX_RSP_STATUS(map_rings_rsp->regcnt_status);
3038
3039        if (err) {
3040                device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
3041                return (-1);
3042        }
3043
3044        return (0);
3045}
3046
3047/*
3048 * Name: qla_init_rcv_cntxt
3049 * Function: Creates the Receive Context.
3050 */
3051static int
3052qla_init_rcv_cntxt(qla_host_t *ha)
3053{
3054	q80_rq_rcv_cntxt_t	*rcntxt;
3055	q80_rsp_rcv_cntxt_t	*rcntxt_rsp;
3056	q80_stat_desc_t		*sdesc;
3057	int			i, j;
3058        qla_hw_t		*hw = &ha->hw;
3059	device_t		dev;
3060	uint32_t		err;
3061	uint32_t		rcntxt_sds_rings;
3062	uint32_t		rcntxt_rds_rings;
3063	uint32_t		max_idx;
3064
3065	dev = ha->pci_dev;
3066
3067	/*
3068	 * Create Receive Context
3069	 */
3070
3071	for (i = 0; i < hw->num_sds_rings; i++) {
3072		sdesc = (q80_stat_desc_t *)&hw->sds[i].sds_ring_base[0];
3073
3074		for (j = 0; j < NUM_STATUS_DESCRIPTORS; j++) {
3075			sdesc->data[0] = 1ULL;
3076			sdesc->data[1] = 1ULL;
3077		}
3078	}
3079
3080	rcntxt_sds_rings = hw->num_sds_rings;
3081	if (hw->num_sds_rings > MAX_RCNTXT_SDS_RINGS)
3082		rcntxt_sds_rings = MAX_RCNTXT_SDS_RINGS;
3083
3084	rcntxt_rds_rings = hw->num_rds_rings;
3085
3086	if (hw->num_rds_rings > MAX_RDS_RING_SETS)
3087		rcntxt_rds_rings = MAX_RDS_RING_SETS;
3088
3089	rcntxt = (q80_rq_rcv_cntxt_t *)ha->hw.mbox;
3090	bzero(rcntxt, (sizeof (q80_rq_rcv_cntxt_t)));
3091
3092	rcntxt->opcode = Q8_MBX_CREATE_RX_CNTXT;
3093	rcntxt->count_version = (sizeof (q80_rq_rcv_cntxt_t) >> 2);
3094	rcntxt->count_version |= Q8_MBX_CMD_VERSION;
3095
3096	rcntxt->cap0 = Q8_RCV_CNTXT_CAP0_BASEFW |
3097			Q8_RCV_CNTXT_CAP0_LRO |
3098			Q8_RCV_CNTXT_CAP0_HW_LRO |
3099			Q8_RCV_CNTXT_CAP0_RSS |
3100			Q8_RCV_CNTXT_CAP0_SGL_LRO;
3101
3102	if (ha->hw.enable_9kb)
3103		rcntxt->cap0 |= Q8_RCV_CNTXT_CAP0_SINGLE_JUMBO;
3104	else
3105		rcntxt->cap0 |= Q8_RCV_CNTXT_CAP0_SGL_JUMBO;
3106
3107	if (ha->hw.num_rds_rings > 1) {
3108		rcntxt->nrds_sets_rings = rcntxt_rds_rings | (1 << 5);
3109		rcntxt->cap0 |= Q8_RCV_CNTXT_CAP0_MULTI_RDS;
3110	} else
3111		rcntxt->nrds_sets_rings = 0x1 | (1 << 5);
3112
3113	rcntxt->nsds_rings = rcntxt_sds_rings;
3114
3115	rcntxt->rds_producer_mode = Q8_RCV_CNTXT_RDS_PROD_MODE_UNIQUE;
3116
3117	rcntxt->rcv_vpid = 0;
3118
3119	for (i = 0; i <  rcntxt_sds_rings; i++) {
3120		rcntxt->sds[i].paddr =
3121			qla_host_to_le64(hw->dma_buf.sds_ring[i].dma_addr);
3122		rcntxt->sds[i].size =
3123			qla_host_to_le32(NUM_STATUS_DESCRIPTORS);
3124		rcntxt->sds[i].intr_id = qla_host_to_le16(hw->intr_id[i]);
3125		rcntxt->sds[i].intr_src_bit = qla_host_to_le16(0);
3126	}
3127
3128	for (i = 0; i <  rcntxt_rds_rings; i++) {
3129		rcntxt->rds[i].paddr_std =
3130			qla_host_to_le64(hw->dma_buf.rds_ring[i].dma_addr);
3131
3132		if (ha->hw.enable_9kb)
3133			rcntxt->rds[i].std_bsize =
3134				qla_host_to_le64(MJUM9BYTES);
3135		else
3136			rcntxt->rds[i].std_bsize = qla_host_to_le64(MCLBYTES);
3137
3138		rcntxt->rds[i].std_nentries =
3139			qla_host_to_le32(NUM_RX_DESCRIPTORS);
3140	}
3141
3142        if (qla_mbx_cmd(ha, (uint32_t *)rcntxt,
3143		(sizeof (q80_rq_rcv_cntxt_t) >> 2),
3144                ha->hw.mbox, (sizeof(q80_rsp_rcv_cntxt_t) >> 2), 0)) {
3145                device_printf(dev, "%s: failed0\n", __func__);
3146                return (-1);
3147        }
3148
3149        rcntxt_rsp = (q80_rsp_rcv_cntxt_t *)ha->hw.mbox;
3150
3151        err = Q8_MBX_RSP_STATUS(rcntxt_rsp->regcnt_status);
3152
3153        if (err) {
3154                device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
3155                return (-1);
3156        }
3157
3158	for (i = 0; i <  rcntxt_sds_rings; i++) {
3159		hw->sds[i].sds_consumer = rcntxt_rsp->sds_cons[i];
3160	}
3161
3162	for (i = 0; i <  rcntxt_rds_rings; i++) {
3163		hw->rds[i].prod_std = rcntxt_rsp->rds[i].prod_std;
3164	}
3165
3166	hw->rcv_cntxt_id = rcntxt_rsp->cntxt_id;
3167
3168	ha->hw.flags.init_rx_cnxt = 1;
3169
3170	if (hw->num_sds_rings > MAX_RCNTXT_SDS_RINGS) {
3171		for (i = MAX_RCNTXT_SDS_RINGS; i < hw->num_sds_rings;) {
3172			if ((i + MAX_RCNTXT_SDS_RINGS) < hw->num_sds_rings)
3173				max_idx = MAX_RCNTXT_SDS_RINGS;
3174			else
3175				max_idx = hw->num_sds_rings - i;
3176
3177			err = qla_add_rcv_rings(ha, i, max_idx);
3178			if (err)
3179				return -1;
3180
3181			i += max_idx;
3182		}
3183	}
3184
3185	if (hw->num_rds_rings > 1) {
3186		for (i = 0; i < hw->num_rds_rings; ) {
3187			if ((i + MAX_SDS_TO_RDS_MAP) < hw->num_rds_rings)
3188				max_idx = MAX_SDS_TO_RDS_MAP;
3189			else
3190				max_idx = hw->num_rds_rings - i;
3191
3192			err = qla_map_sds_to_rds(ha, i, max_idx);
3193			if (err)
3194				return -1;
3195
3196			i += max_idx;
3197		}
3198	}
3199
3200	return (0);
3201}
3202
3203static int
3204qla_add_rcv_rings(qla_host_t *ha, uint32_t sds_idx, uint32_t nsds)
3205{
3206	device_t		dev = ha->pci_dev;
3207	q80_rq_add_rcv_rings_t	*add_rcv;
3208	q80_rsp_add_rcv_rings_t	*add_rcv_rsp;
3209	uint32_t		i,j, err;
3210        qla_hw_t		*hw = &ha->hw;
3211
3212	add_rcv = (q80_rq_add_rcv_rings_t *)ha->hw.mbox;
3213	bzero(add_rcv, sizeof (q80_rq_add_rcv_rings_t));
3214
3215	add_rcv->opcode = Q8_MBX_ADD_RX_RINGS;
3216	add_rcv->count_version = (sizeof (q80_rq_add_rcv_rings_t) >> 2);
3217	add_rcv->count_version |= Q8_MBX_CMD_VERSION;
3218
3219	add_rcv->nrds_sets_rings = nsds | (1 << 5);
3220	add_rcv->nsds_rings = nsds;
3221	add_rcv->cntxt_id = hw->rcv_cntxt_id;
3222
3223        for (i = 0; i <  nsds; i++) {
3224		j = i + sds_idx;
3225
3226                add_rcv->sds[i].paddr =
3227                        qla_host_to_le64(hw->dma_buf.sds_ring[j].dma_addr);
3228
3229                add_rcv->sds[i].size =
3230                        qla_host_to_le32(NUM_STATUS_DESCRIPTORS);
3231
3232                add_rcv->sds[i].intr_id = qla_host_to_le16(hw->intr_id[j]);
3233                add_rcv->sds[i].intr_src_bit = qla_host_to_le16(0);
3234        }
3235
3236        for (i = 0; (i <  nsds); i++) {
3237                j = i + sds_idx;
3238
3239                add_rcv->rds[i].paddr_std =
3240                        qla_host_to_le64(hw->dma_buf.rds_ring[j].dma_addr);
3241
3242		if (ha->hw.enable_9kb)
3243			add_rcv->rds[i].std_bsize =
3244				qla_host_to_le64(MJUM9BYTES);
3245		else
3246                	add_rcv->rds[i].std_bsize = qla_host_to_le64(MCLBYTES);
3247
3248                add_rcv->rds[i].std_nentries =
3249                        qla_host_to_le32(NUM_RX_DESCRIPTORS);
3250        }
3251
3252        if (qla_mbx_cmd(ha, (uint32_t *)add_rcv,
3253		(sizeof (q80_rq_add_rcv_rings_t) >> 2),
3254                ha->hw.mbox, (sizeof(q80_rsp_add_rcv_rings_t) >> 2), 0)) {
3255                device_printf(dev, "%s: failed0\n", __func__);
3256                return (-1);
3257        }
3258
3259        add_rcv_rsp = (q80_rsp_add_rcv_rings_t *)ha->hw.mbox;
3260
3261        err = Q8_MBX_RSP_STATUS(add_rcv_rsp->regcnt_status);
3262
3263        if (err) {
3264                device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
3265                return (-1);
3266        }
3267
3268	for (i = 0; i < nsds; i++) {
3269		hw->sds[(i + sds_idx)].sds_consumer = add_rcv_rsp->sds_cons[i];
3270	}
3271
3272	for (i = 0; i < nsds; i++) {
3273		hw->rds[(i + sds_idx)].prod_std = add_rcv_rsp->rds[i].prod_std;
3274	}
3275
3276	return (0);
3277}
3278
3279/*
3280 * Name: qla_del_rcv_cntxt
3281 * Function: Destroys the Receive Context.
3282 */
3283static void
3284qla_del_rcv_cntxt(qla_host_t *ha)
3285{
3286	device_t			dev = ha->pci_dev;
3287	q80_rcv_cntxt_destroy_t		*rcntxt;
3288	q80_rcv_cntxt_destroy_rsp_t	*rcntxt_rsp;
3289	uint32_t			err;
3290	uint8_t				bcast_mac[6];
3291
3292	if (!ha->hw.flags.init_rx_cnxt)
3293		return;
3294
3295	if (qla_hw_del_all_mcast(ha))
3296		return;
3297
3298	if (ha->hw.flags.bcast_mac) {
3299		bcast_mac[0] = 0xFF; bcast_mac[1] = 0xFF; bcast_mac[2] = 0xFF;
3300		bcast_mac[3] = 0xFF; bcast_mac[4] = 0xFF; bcast_mac[5] = 0xFF;
3301
3302		if (qla_config_mac_addr(ha, bcast_mac, 0, 1))
3303			return;
3304		ha->hw.flags.bcast_mac = 0;
3305	}
3306
3307	if (ha->hw.flags.unicast_mac) {
3308		if (qla_config_mac_addr(ha, ha->hw.mac_addr, 0, 1))
3309			return;
3310		ha->hw.flags.unicast_mac = 0;
3311	}
3312
3313	rcntxt = (q80_rcv_cntxt_destroy_t *)ha->hw.mbox;
3314	bzero(rcntxt, (sizeof (q80_rcv_cntxt_destroy_t)));
3315
3316	rcntxt->opcode = Q8_MBX_DESTROY_RX_CNTXT;
3317	rcntxt->count_version = (sizeof (q80_rcv_cntxt_destroy_t) >> 2);
3318	rcntxt->count_version |= Q8_MBX_CMD_VERSION;
3319
3320	rcntxt->cntxt_id = ha->hw.rcv_cntxt_id;
3321
3322        if (qla_mbx_cmd(ha, (uint32_t *)rcntxt,
3323		(sizeof (q80_rcv_cntxt_destroy_t) >> 2),
3324                ha->hw.mbox, (sizeof(q80_rcv_cntxt_destroy_rsp_t) >> 2), 0)) {
3325                device_printf(dev, "%s: failed0\n", __func__);
3326                return;
3327        }
3328        rcntxt_rsp = (q80_rcv_cntxt_destroy_rsp_t *)ha->hw.mbox;
3329
3330        err = Q8_MBX_RSP_STATUS(rcntxt_rsp->regcnt_status);
3331
3332        if (err) {
3333                device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
3334        }
3335
3336	ha->hw.flags.init_rx_cnxt = 0;
3337	return;
3338}
3339
3340/*
3341 * Name: qla_init_xmt_cntxt
3342 * Function: Creates the Transmit Context.
3343 */
3344static int
3345qla_init_xmt_cntxt_i(qla_host_t *ha, uint32_t txr_idx)
3346{
3347	device_t		dev;
3348        qla_hw_t		*hw = &ha->hw;
3349	q80_rq_tx_cntxt_t	*tcntxt;
3350	q80_rsp_tx_cntxt_t	*tcntxt_rsp;
3351	uint32_t		err;
3352	qla_hw_tx_cntxt_t       *hw_tx_cntxt;
3353	uint32_t		intr_idx;
3354
3355	hw_tx_cntxt = &hw->tx_cntxt[txr_idx];
3356
3357	dev = ha->pci_dev;
3358
3359	/*
3360	 * Create Transmit Context
3361	 */
3362	tcntxt = (q80_rq_tx_cntxt_t *)ha->hw.mbox;
3363	bzero(tcntxt, (sizeof (q80_rq_tx_cntxt_t)));
3364
3365	tcntxt->opcode = Q8_MBX_CREATE_TX_CNTXT;
3366	tcntxt->count_version = (sizeof (q80_rq_tx_cntxt_t) >> 2);
3367	tcntxt->count_version |= Q8_MBX_CMD_VERSION;
3368
3369	intr_idx = txr_idx;
3370
3371#ifdef QL_ENABLE_ISCSI_TLV
3372
3373	tcntxt->cap0 = Q8_TX_CNTXT_CAP0_BASEFW | Q8_TX_CNTXT_CAP0_LSO |
3374				Q8_TX_CNTXT_CAP0_TC;
3375
3376	if (txr_idx >= (ha->hw.num_tx_rings >> 1)) {
3377		tcntxt->traffic_class = 1;
3378	}
3379
3380	intr_idx = txr_idx % (ha->hw.num_tx_rings >> 1);
3381
3382#else
3383	tcntxt->cap0 = Q8_TX_CNTXT_CAP0_BASEFW | Q8_TX_CNTXT_CAP0_LSO;
3384
3385#endif /* #ifdef QL_ENABLE_ISCSI_TLV */
3386
3387	tcntxt->ntx_rings = 1;
3388
3389	tcntxt->tx_ring[0].paddr =
3390		qla_host_to_le64(hw_tx_cntxt->tx_ring_paddr);
3391	tcntxt->tx_ring[0].tx_consumer =
3392		qla_host_to_le64(hw_tx_cntxt->tx_cons_paddr);
3393	tcntxt->tx_ring[0].nentries = qla_host_to_le16(NUM_TX_DESCRIPTORS);
3394
3395	tcntxt->tx_ring[0].intr_id = qla_host_to_le16(hw->intr_id[intr_idx]);
3396	tcntxt->tx_ring[0].intr_src_bit = qla_host_to_le16(0);
3397
3398	hw_tx_cntxt->txr_free = NUM_TX_DESCRIPTORS;
3399	hw_tx_cntxt->txr_next = hw_tx_cntxt->txr_comp = 0;
3400	*(hw_tx_cntxt->tx_cons) = 0;
3401
3402        if (qla_mbx_cmd(ha, (uint32_t *)tcntxt,
3403		(sizeof (q80_rq_tx_cntxt_t) >> 2),
3404                ha->hw.mbox,
3405		(sizeof(q80_rsp_tx_cntxt_t) >> 2), 0)) {
3406                device_printf(dev, "%s: failed0\n", __func__);
3407                return (-1);
3408        }
3409        tcntxt_rsp = (q80_rsp_tx_cntxt_t *)ha->hw.mbox;
3410
3411        err = Q8_MBX_RSP_STATUS(tcntxt_rsp->regcnt_status);
3412
3413        if (err) {
3414                device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
3415		return -1;
3416        }
3417
3418	hw_tx_cntxt->tx_prod_reg = tcntxt_rsp->tx_ring[0].prod_index;
3419	hw_tx_cntxt->tx_cntxt_id = tcntxt_rsp->tx_ring[0].cntxt_id;
3420
3421	if (qla_config_intr_coalesce(ha, hw_tx_cntxt->tx_cntxt_id, 0, 0))
3422		return (-1);
3423
3424	return (0);
3425}
3426
3427/*
3428 * Name: qla_del_xmt_cntxt
3429 * Function: Destroys the Transmit Context.
3430 */
3431static int
3432qla_del_xmt_cntxt_i(qla_host_t *ha, uint32_t txr_idx)
3433{
3434	device_t			dev = ha->pci_dev;
3435	q80_tx_cntxt_destroy_t		*tcntxt;
3436	q80_tx_cntxt_destroy_rsp_t	*tcntxt_rsp;
3437	uint32_t			err;
3438
3439	tcntxt = (q80_tx_cntxt_destroy_t *)ha->hw.mbox;
3440	bzero(tcntxt, (sizeof (q80_tx_cntxt_destroy_t)));
3441
3442	tcntxt->opcode = Q8_MBX_DESTROY_TX_CNTXT;
3443	tcntxt->count_version = (sizeof (q80_tx_cntxt_destroy_t) >> 2);
3444	tcntxt->count_version |= Q8_MBX_CMD_VERSION;
3445
3446	tcntxt->cntxt_id = ha->hw.tx_cntxt[txr_idx].tx_cntxt_id;
3447
3448        if (qla_mbx_cmd(ha, (uint32_t *)tcntxt,
3449		(sizeof (q80_tx_cntxt_destroy_t) >> 2),
3450                ha->hw.mbox, (sizeof (q80_tx_cntxt_destroy_rsp_t) >> 2), 0)) {
3451                device_printf(dev, "%s: failed0\n", __func__);
3452                return (-1);
3453        }
3454        tcntxt_rsp = (q80_tx_cntxt_destroy_rsp_t *)ha->hw.mbox;
3455
3456        err = Q8_MBX_RSP_STATUS(tcntxt_rsp->regcnt_status);
3457
3458        if (err) {
3459                device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
3460		return (-1);
3461        }
3462
3463	return (0);
3464}
3465static int
3466qla_del_xmt_cntxt(qla_host_t *ha)
3467{
3468	uint32_t i;
3469	int ret = 0;
3470
3471	if (!ha->hw.flags.init_tx_cnxt)
3472		return (ret);
3473
3474	for (i = 0; i < ha->hw.num_tx_rings; i++) {
3475		if ((ret = qla_del_xmt_cntxt_i(ha, i)) != 0)
3476			break;
3477	}
3478	ha->hw.flags.init_tx_cnxt = 0;
3479
3480	return (ret);
3481}
3482
3483static int
3484qla_init_xmt_cntxt(qla_host_t *ha)
3485{
3486	uint32_t i, j;
3487
3488	for (i = 0; i < ha->hw.num_tx_rings; i++) {
3489		if (qla_init_xmt_cntxt_i(ha, i) != 0) {
3490			for (j = 0; j < i; j++) {
3491				if (qla_del_xmt_cntxt_i(ha, j))
3492					break;
3493			}
3494			return (-1);
3495		}
3496	}
3497	ha->hw.flags.init_tx_cnxt = 1;
3498	return (0);
3499}
3500
3501static int
3502qla_hw_all_mcast(qla_host_t *ha, uint32_t add_mcast)
3503{
3504	int i, nmcast;
3505	uint32_t count = 0;
3506	uint8_t *mcast;
3507
3508	nmcast = ha->hw.nmcast;
3509
3510	QL_DPRINT2(ha, (ha->pci_dev,
3511		"%s:[0x%x] enter nmcast = %d \n", __func__, add_mcast, nmcast));
3512
3513	mcast = ha->hw.mac_addr_arr;
3514	memset(mcast, 0, (Q8_MAX_MAC_ADDRS * ETHER_ADDR_LEN));
3515
3516	for (i = 0 ; ((i < Q8_MAX_NUM_MULTICAST_ADDRS) && nmcast); i++) {
3517		if ((ha->hw.mcast[i].addr[0] != 0) ||
3518			(ha->hw.mcast[i].addr[1] != 0) ||
3519			(ha->hw.mcast[i].addr[2] != 0) ||
3520			(ha->hw.mcast[i].addr[3] != 0) ||
3521			(ha->hw.mcast[i].addr[4] != 0) ||
3522			(ha->hw.mcast[i].addr[5] != 0)) {
3523			bcopy(ha->hw.mcast[i].addr, mcast, ETHER_ADDR_LEN);
3524			mcast = mcast + ETHER_ADDR_LEN;
3525			count++;
3526
3527			device_printf(ha->pci_dev,
3528				"%s: %x:%x:%x:%x:%x:%x \n",
3529				__func__, ha->hw.mcast[i].addr[0],
3530				ha->hw.mcast[i].addr[1], ha->hw.mcast[i].addr[2],
3531				ha->hw.mcast[i].addr[3], ha->hw.mcast[i].addr[4],
3532				ha->hw.mcast[i].addr[5]);
3533
3534			if (count == Q8_MAX_MAC_ADDRS) {
3535				if (qla_config_mac_addr(ha, ha->hw.mac_addr_arr,
3536					add_mcast, count)) {
3537                			device_printf(ha->pci_dev,
3538						"%s: failed\n", __func__);
3539					return (-1);
3540				}
3541
3542				count = 0;
3543				mcast = ha->hw.mac_addr_arr;
3544				memset(mcast, 0,
3545					(Q8_MAX_MAC_ADDRS * ETHER_ADDR_LEN));
3546			}
3547
3548			nmcast--;
3549		}
3550	}
3551
3552	if (count) {
3553		if (qla_config_mac_addr(ha, ha->hw.mac_addr_arr, add_mcast,
3554			count)) {
3555                	device_printf(ha->pci_dev, "%s: failed\n", __func__);
3556			return (-1);
3557		}
3558	}
3559	QL_DPRINT2(ha, (ha->pci_dev,
3560		"%s:[0x%x] exit nmcast = %d \n", __func__, add_mcast, nmcast));
3561
3562	return 0;
3563}
3564
3565static int
3566qla_hw_add_all_mcast(qla_host_t *ha)
3567{
3568	int ret;
3569
3570	ret = qla_hw_all_mcast(ha, 1);
3571
3572	return (ret);
3573}
3574
3575int
3576qla_hw_del_all_mcast(qla_host_t *ha)
3577{
3578	int ret;
3579
3580	ret = qla_hw_all_mcast(ha, 0);
3581
3582	bzero(ha->hw.mcast, (sizeof (qla_mcast_t) * Q8_MAX_NUM_MULTICAST_ADDRS));
3583	ha->hw.nmcast = 0;
3584
3585	return (ret);
3586}
3587
3588static int
3589qla_hw_mac_addr_present(qla_host_t *ha, uint8_t *mta)
3590{
3591	int i;
3592
3593	for (i = 0; i < Q8_MAX_NUM_MULTICAST_ADDRS; i++) {
3594		if (QL_MAC_CMP(ha->hw.mcast[i].addr, mta) == 0)
3595			return (0); /* its been already added */
3596	}
3597	return (-1);
3598}
3599
3600static int
3601qla_hw_add_mcast(qla_host_t *ha, uint8_t *mta, uint32_t nmcast)
3602{
3603	int i;
3604
3605	for (i = 0; i < Q8_MAX_NUM_MULTICAST_ADDRS; i++) {
3606		if ((ha->hw.mcast[i].addr[0] == 0) &&
3607			(ha->hw.mcast[i].addr[1] == 0) &&
3608			(ha->hw.mcast[i].addr[2] == 0) &&
3609			(ha->hw.mcast[i].addr[3] == 0) &&
3610			(ha->hw.mcast[i].addr[4] == 0) &&
3611			(ha->hw.mcast[i].addr[5] == 0)) {
3612			bcopy(mta, ha->hw.mcast[i].addr, Q8_MAC_ADDR_LEN);
3613			ha->hw.nmcast++;
3614
3615			mta = mta + ETHER_ADDR_LEN;
3616			nmcast--;
3617
3618			if (nmcast == 0)
3619				break;
3620		}
3621	}
3622	return 0;
3623}
3624
3625static int
3626qla_hw_del_mcast(qla_host_t *ha, uint8_t *mta, uint32_t nmcast)
3627{
3628	int i;
3629
3630	for (i = 0; i < Q8_MAX_NUM_MULTICAST_ADDRS; i++) {
3631		if (QL_MAC_CMP(ha->hw.mcast[i].addr, mta) == 0) {
3632			ha->hw.mcast[i].addr[0] = 0;
3633			ha->hw.mcast[i].addr[1] = 0;
3634			ha->hw.mcast[i].addr[2] = 0;
3635			ha->hw.mcast[i].addr[3] = 0;
3636			ha->hw.mcast[i].addr[4] = 0;
3637			ha->hw.mcast[i].addr[5] = 0;
3638
3639			ha->hw.nmcast--;
3640
3641			mta = mta + ETHER_ADDR_LEN;
3642			nmcast--;
3643
3644			if (nmcast == 0)
3645				break;
3646		}
3647	}
3648	return 0;
3649}
3650
3651/*
3652 * Name: ql_hw_set_multi
3653 * Function: Sets the Multicast Addresses provided by the host O.S into the
3654 *	hardware (for the given interface)
3655 */
3656int
3657ql_hw_set_multi(qla_host_t *ha, uint8_t *mcast_addr, uint32_t mcnt,
3658	uint32_t add_mac)
3659{
3660	uint8_t *mta = mcast_addr;
3661	int i;
3662	int ret = 0;
3663	uint32_t count = 0;
3664	uint8_t *mcast;
3665
3666	mcast = ha->hw.mac_addr_arr;
3667	memset(mcast, 0, (Q8_MAX_MAC_ADDRS * ETHER_ADDR_LEN));
3668
3669	for (i = 0; i < mcnt; i++) {
3670		if (mta[0] || mta[1] || mta[2] || mta[3] || mta[4] || mta[5]) {
3671			if (add_mac) {
3672				if (qla_hw_mac_addr_present(ha, mta) != 0) {
3673					bcopy(mta, mcast, ETHER_ADDR_LEN);
3674					mcast = mcast + ETHER_ADDR_LEN;
3675					count++;
3676				}
3677			} else {
3678				if (qla_hw_mac_addr_present(ha, mta) == 0) {
3679					bcopy(mta, mcast, ETHER_ADDR_LEN);
3680					mcast = mcast + ETHER_ADDR_LEN;
3681					count++;
3682				}
3683			}
3684		}
3685		if (count == Q8_MAX_MAC_ADDRS) {
3686			if (qla_config_mac_addr(ha, ha->hw.mac_addr_arr,
3687				add_mac, count)) {
3688                		device_printf(ha->pci_dev, "%s: failed\n",
3689					__func__);
3690				return (-1);
3691			}
3692
3693			if (add_mac) {
3694				qla_hw_add_mcast(ha, ha->hw.mac_addr_arr,
3695					count);
3696			} else {
3697				qla_hw_del_mcast(ha, ha->hw.mac_addr_arr,
3698					count);
3699			}
3700
3701			count = 0;
3702			mcast = ha->hw.mac_addr_arr;
3703			memset(mcast, 0, (Q8_MAX_MAC_ADDRS * ETHER_ADDR_LEN));
3704		}
3705
3706		mta += Q8_MAC_ADDR_LEN;
3707	}
3708
3709	if (count) {
3710		if (qla_config_mac_addr(ha, ha->hw.mac_addr_arr, add_mac,
3711			count)) {
3712                	device_printf(ha->pci_dev, "%s: failed\n", __func__);
3713			return (-1);
3714		}
3715		if (add_mac) {
3716			qla_hw_add_mcast(ha, ha->hw.mac_addr_arr, count);
3717		} else {
3718			qla_hw_del_mcast(ha, ha->hw.mac_addr_arr, count);
3719		}
3720	}
3721
3722	return (ret);
3723}
3724
3725/*
3726 * Name: ql_hw_tx_done_locked
3727 * Function: Handle Transmit Completions
3728 */
3729void
3730ql_hw_tx_done_locked(qla_host_t *ha, uint32_t txr_idx)
3731{
3732	qla_tx_buf_t *txb;
3733        qla_hw_t *hw = &ha->hw;
3734	uint32_t comp_idx, comp_count = 0;
3735	qla_hw_tx_cntxt_t *hw_tx_cntxt;
3736
3737	hw_tx_cntxt = &hw->tx_cntxt[txr_idx];
3738
3739	/* retrieve index of last entry in tx ring completed */
3740	comp_idx = qla_le32_to_host(*(hw_tx_cntxt->tx_cons));
3741
3742	while (comp_idx != hw_tx_cntxt->txr_comp) {
3743		txb = &ha->tx_ring[txr_idx].tx_buf[hw_tx_cntxt->txr_comp];
3744
3745		hw_tx_cntxt->txr_comp++;
3746		if (hw_tx_cntxt->txr_comp == NUM_TX_DESCRIPTORS)
3747			hw_tx_cntxt->txr_comp = 0;
3748
3749		comp_count++;
3750
3751		if (txb->m_head) {
3752			if_inc_counter(ha->ifp, IFCOUNTER_OPACKETS, 1);
3753
3754			bus_dmamap_sync(ha->tx_tag, txb->map,
3755				BUS_DMASYNC_POSTWRITE);
3756			bus_dmamap_unload(ha->tx_tag, txb->map);
3757			m_freem(txb->m_head);
3758
3759			txb->m_head = NULL;
3760		}
3761	}
3762
3763	hw_tx_cntxt->txr_free += comp_count;
3764
3765	if (hw_tx_cntxt->txr_free > NUM_TX_DESCRIPTORS)
3766		device_printf(ha->pci_dev, "%s [%d]: txr_idx = %d txr_free = %d"
3767			"txr_next = %d txr_comp = %d\n", __func__, __LINE__,
3768			txr_idx, hw_tx_cntxt->txr_free,
3769			hw_tx_cntxt->txr_next, hw_tx_cntxt->txr_comp);
3770
3771	QL_ASSERT(ha, (hw_tx_cntxt->txr_free <= NUM_TX_DESCRIPTORS), \
3772		("%s [%d]: txr_idx = %d txr_free = %d txr_next = %d txr_comp = %d\n",\
3773		__func__, __LINE__, txr_idx, hw_tx_cntxt->txr_free, \
3774		hw_tx_cntxt->txr_next, hw_tx_cntxt->txr_comp));
3775
3776	return;
3777}
3778
3779void
3780ql_update_link_state(qla_host_t *ha)
3781{
3782	uint32_t link_state = 0;
3783	uint32_t prev_link_state;
3784
3785	prev_link_state =  ha->hw.link_up;
3786
3787	if (if_getdrvflags(ha->ifp) & IFF_DRV_RUNNING) {
3788		link_state = READ_REG32(ha, Q8_LINK_STATE);
3789
3790		if (ha->pci_func == 0) {
3791			link_state = (((link_state & 0xF) == 1)? 1 : 0);
3792		} else {
3793			link_state = ((((link_state >> 4)& 0xF) == 1)? 1 : 0);
3794		}
3795	}
3796
3797	atomic_store_rel_8(&ha->hw.link_up, (uint8_t)link_state);
3798
3799	if (prev_link_state !=  ha->hw.link_up) {
3800		if (ha->hw.link_up) {
3801			if_link_state_change(ha->ifp, LINK_STATE_UP);
3802		} else {
3803			if_link_state_change(ha->ifp, LINK_STATE_DOWN);
3804		}
3805	}
3806	return;
3807}
3808
3809int
3810ql_hw_check_health(qla_host_t *ha)
3811{
3812	uint32_t val;
3813
3814	ha->hw.health_count++;
3815
3816	if (ha->hw.health_count < 500)
3817		return 0;
3818
3819	ha->hw.health_count = 0;
3820
3821	val = READ_REG32(ha, Q8_ASIC_TEMPERATURE);
3822
3823	if (((val & 0xFFFF) == 2) || ((val & 0xFFFF) == 3) ||
3824		(QL_ERR_INJECT(ha, INJCT_TEMPERATURE_FAILURE))) {
3825		device_printf(ha->pci_dev, "%s: Temperature Alert"
3826			" at ts_usecs %ld ts_reg = 0x%08x\n",
3827			__func__, qla_get_usec_timestamp(), val);
3828
3829		if (ha->hw.sp_log_stop_events & Q8_SP_LOG_STOP_TEMP_FAILURE)
3830			ha->hw.sp_log_stop = -1;
3831
3832		QL_INITIATE_RECOVERY(ha);
3833		return -1;
3834	}
3835
3836	val = READ_REG32(ha, Q8_FIRMWARE_HEARTBEAT);
3837
3838	if ((val != ha->hw.hbeat_value) &&
3839		(!(QL_ERR_INJECT(ha, INJCT_HEARTBEAT_FAILURE)))) {
3840		ha->hw.hbeat_value = val;
3841		ha->hw.hbeat_failure = 0;
3842		return 0;
3843	}
3844
3845	ha->hw.hbeat_failure++;
3846
3847	if ((ha->dbg_level & 0x8000) && (ha->hw.hbeat_failure == 1))
3848		device_printf(ha->pci_dev, "%s: Heartbeat Failue 1[0x%08x]\n",
3849			__func__, val);
3850	if (ha->hw.hbeat_failure < 2) /* we ignore the first failure */
3851		return 0;
3852	else {
3853		uint32_t peg_halt_status1;
3854		uint32_t peg_halt_status2;
3855
3856		peg_halt_status1 = READ_REG32(ha, Q8_PEG_HALT_STATUS1);
3857		peg_halt_status2 = READ_REG32(ha, Q8_PEG_HALT_STATUS2);
3858
3859		device_printf(ha->pci_dev,
3860			"%s: Heartbeat Failue at ts_usecs = %ld "
3861			"fw_heart_beat = 0x%08x "
3862			"peg_halt_status1 = 0x%08x "
3863			"peg_halt_status2 = 0x%08x\n",
3864			__func__, qla_get_usec_timestamp(), val,
3865			peg_halt_status1, peg_halt_status2);
3866
3867		if (ha->hw.sp_log_stop_events & Q8_SP_LOG_STOP_HBEAT_FAILURE)
3868			ha->hw.sp_log_stop = -1;
3869	}
3870	QL_INITIATE_RECOVERY(ha);
3871
3872	return -1;
3873}
3874
3875static int
3876qla_init_nic_func(qla_host_t *ha)
3877{
3878        device_t                dev;
3879        q80_init_nic_func_t     *init_nic;
3880        q80_init_nic_func_rsp_t *init_nic_rsp;
3881        uint32_t                err;
3882
3883        dev = ha->pci_dev;
3884
3885        init_nic = (q80_init_nic_func_t *)ha->hw.mbox;
3886        bzero(init_nic, sizeof(q80_init_nic_func_t));
3887
3888        init_nic->opcode = Q8_MBX_INIT_NIC_FUNC;
3889        init_nic->count_version = (sizeof (q80_init_nic_func_t) >> 2);
3890        init_nic->count_version |= Q8_MBX_CMD_VERSION;
3891
3892        init_nic->options = Q8_INIT_NIC_REG_DCBX_CHNG_AEN;
3893        init_nic->options |= Q8_INIT_NIC_REG_SFP_CHNG_AEN;
3894        init_nic->options |= Q8_INIT_NIC_REG_IDC_AEN;
3895
3896//qla_dump_buf8(ha, __func__, init_nic, sizeof (q80_init_nic_func_t));
3897        if (qla_mbx_cmd(ha, (uint32_t *)init_nic,
3898                (sizeof (q80_init_nic_func_t) >> 2),
3899                ha->hw.mbox, (sizeof (q80_init_nic_func_rsp_t) >> 2), 0)) {
3900                device_printf(dev, "%s: failed\n", __func__);
3901                return -1;
3902        }
3903
3904        init_nic_rsp = (q80_init_nic_func_rsp_t *)ha->hw.mbox;
3905// qla_dump_buf8(ha, __func__, init_nic_rsp, sizeof (q80_init_nic_func_rsp_t));
3906
3907        err = Q8_MBX_RSP_STATUS(init_nic_rsp->regcnt_status);
3908
3909        if (err) {
3910                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
3911        } else {
3912                device_printf(dev, "%s: successful\n", __func__);
3913	}
3914
3915        return 0;
3916}
3917
3918static int
3919qla_stop_nic_func(qla_host_t *ha)
3920{
3921        device_t                dev;
3922        q80_stop_nic_func_t     *stop_nic;
3923        q80_stop_nic_func_rsp_t *stop_nic_rsp;
3924        uint32_t                err;
3925
3926        dev = ha->pci_dev;
3927
3928        stop_nic = (q80_stop_nic_func_t *)ha->hw.mbox;
3929        bzero(stop_nic, sizeof(q80_stop_nic_func_t));
3930
3931        stop_nic->opcode = Q8_MBX_STOP_NIC_FUNC;
3932        stop_nic->count_version = (sizeof (q80_stop_nic_func_t) >> 2);
3933        stop_nic->count_version |= Q8_MBX_CMD_VERSION;
3934
3935        stop_nic->options = Q8_STOP_NIC_DEREG_DCBX_CHNG_AEN;
3936        stop_nic->options |= Q8_STOP_NIC_DEREG_SFP_CHNG_AEN;
3937
3938//qla_dump_buf8(ha, __func__, stop_nic, sizeof (q80_stop_nic_func_t));
3939        if (qla_mbx_cmd(ha, (uint32_t *)stop_nic,
3940                (sizeof (q80_stop_nic_func_t) >> 2),
3941                ha->hw.mbox, (sizeof (q80_stop_nic_func_rsp_t) >> 2), 0)) {
3942                device_printf(dev, "%s: failed\n", __func__);
3943                return -1;
3944        }
3945
3946        stop_nic_rsp = (q80_stop_nic_func_rsp_t *)ha->hw.mbox;
3947//qla_dump_buf8(ha, __func__, stop_nic_rsp, sizeof (q80_stop_nic_func_rsp_ t));
3948
3949        err = Q8_MBX_RSP_STATUS(stop_nic_rsp->regcnt_status);
3950
3951        if (err) {
3952                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
3953        }
3954
3955        return 0;
3956}
3957
3958static int
3959qla_query_fw_dcbx_caps(qla_host_t *ha)
3960{
3961        device_t                        dev;
3962        q80_query_fw_dcbx_caps_t        *fw_dcbx;
3963        q80_query_fw_dcbx_caps_rsp_t    *fw_dcbx_rsp;
3964        uint32_t                        err;
3965
3966        dev = ha->pci_dev;
3967
3968        fw_dcbx = (q80_query_fw_dcbx_caps_t *)ha->hw.mbox;
3969        bzero(fw_dcbx, sizeof(q80_query_fw_dcbx_caps_t));
3970
3971        fw_dcbx->opcode = Q8_MBX_GET_FW_DCBX_CAPS;
3972        fw_dcbx->count_version = (sizeof (q80_query_fw_dcbx_caps_t) >> 2);
3973        fw_dcbx->count_version |= Q8_MBX_CMD_VERSION;
3974
3975        ql_dump_buf8(ha, __func__, fw_dcbx, sizeof (q80_query_fw_dcbx_caps_t));
3976        if (qla_mbx_cmd(ha, (uint32_t *)fw_dcbx,
3977                (sizeof (q80_query_fw_dcbx_caps_t) >> 2),
3978                ha->hw.mbox, (sizeof (q80_query_fw_dcbx_caps_rsp_t) >> 2), 0)) {
3979                device_printf(dev, "%s: failed\n", __func__);
3980                return -1;
3981        }
3982
3983        fw_dcbx_rsp = (q80_query_fw_dcbx_caps_rsp_t *)ha->hw.mbox;
3984        ql_dump_buf8(ha, __func__, fw_dcbx_rsp,
3985                sizeof (q80_query_fw_dcbx_caps_rsp_t));
3986
3987        err = Q8_MBX_RSP_STATUS(fw_dcbx_rsp->regcnt_status);
3988
3989        if (err) {
3990                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
3991        }
3992
3993        return 0;
3994}
3995
3996static int
3997qla_idc_ack(qla_host_t *ha, uint32_t aen_mb1, uint32_t aen_mb2,
3998        uint32_t aen_mb3, uint32_t aen_mb4)
3999{
4000        device_t                dev;
4001        q80_idc_ack_t           *idc_ack;
4002        q80_idc_ack_rsp_t       *idc_ack_rsp;
4003        uint32_t                err;
4004        int                     count = 300;
4005
4006        dev = ha->pci_dev;
4007
4008        idc_ack = (q80_idc_ack_t *)ha->hw.mbox;
4009        bzero(idc_ack, sizeof(q80_idc_ack_t));
4010
4011        idc_ack->opcode = Q8_MBX_IDC_ACK;
4012        idc_ack->count_version = (sizeof (q80_idc_ack_t) >> 2);
4013        idc_ack->count_version |= Q8_MBX_CMD_VERSION;
4014
4015        idc_ack->aen_mb1 = aen_mb1;
4016        idc_ack->aen_mb2 = aen_mb2;
4017        idc_ack->aen_mb3 = aen_mb3;
4018        idc_ack->aen_mb4 = aen_mb4;
4019
4020        ha->hw.imd_compl= 0;
4021
4022        if (qla_mbx_cmd(ha, (uint32_t *)idc_ack,
4023                (sizeof (q80_idc_ack_t) >> 2),
4024                ha->hw.mbox, (sizeof (q80_idc_ack_rsp_t) >> 2), 0)) {
4025                device_printf(dev, "%s: failed\n", __func__);
4026                return -1;
4027        }
4028
4029        idc_ack_rsp = (q80_idc_ack_rsp_t *)ha->hw.mbox;
4030
4031        err = Q8_MBX_RSP_STATUS(idc_ack_rsp->regcnt_status);
4032
4033        if (err) {
4034                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
4035                return(-1);
4036        }
4037
4038        while (count && !ha->hw.imd_compl) {
4039                qla_mdelay(__func__, 100);
4040                count--;
4041        }
4042
4043        if (!count)
4044                return -1;
4045        else
4046                device_printf(dev, "%s: count %d\n", __func__, count);
4047
4048        return (0);
4049}
4050
4051static int
4052qla_set_port_config(qla_host_t *ha, uint32_t cfg_bits)
4053{
4054        device_t                dev;
4055        q80_set_port_cfg_t      *pcfg;
4056        q80_set_port_cfg_rsp_t  *pfg_rsp;
4057        uint32_t                err;
4058        int                     count = 300;
4059
4060        dev = ha->pci_dev;
4061
4062        pcfg = (q80_set_port_cfg_t *)ha->hw.mbox;
4063        bzero(pcfg, sizeof(q80_set_port_cfg_t));
4064
4065        pcfg->opcode = Q8_MBX_SET_PORT_CONFIG;
4066        pcfg->count_version = (sizeof (q80_set_port_cfg_t) >> 2);
4067        pcfg->count_version |= Q8_MBX_CMD_VERSION;
4068
4069        pcfg->cfg_bits = cfg_bits;
4070
4071        device_printf(dev, "%s: cfg_bits"
4072                " [STD_PAUSE_DIR, PAUSE_TYPE, DCBX]"
4073                " [0x%x, 0x%x, 0x%x]\n", __func__,
4074                ((cfg_bits & Q8_PORT_CFG_BITS_STDPAUSE_DIR_MASK)>>20),
4075                ((cfg_bits & Q8_PORT_CFG_BITS_PAUSE_CFG_MASK) >> 5),
4076                ((cfg_bits & Q8_PORT_CFG_BITS_DCBX_ENABLE) ? 1: 0));
4077
4078        ha->hw.imd_compl= 0;
4079
4080        if (qla_mbx_cmd(ha, (uint32_t *)pcfg,
4081                (sizeof (q80_set_port_cfg_t) >> 2),
4082                ha->hw.mbox, (sizeof (q80_set_port_cfg_rsp_t) >> 2), 0)) {
4083                device_printf(dev, "%s: failed\n", __func__);
4084                return -1;
4085        }
4086
4087        pfg_rsp = (q80_set_port_cfg_rsp_t *)ha->hw.mbox;
4088
4089        err = Q8_MBX_RSP_STATUS(pfg_rsp->regcnt_status);
4090
4091        if (err == Q8_MBX_RSP_IDC_INTRMD_RSP) {
4092                while (count && !ha->hw.imd_compl) {
4093                        qla_mdelay(__func__, 100);
4094                        count--;
4095                }
4096                if (count) {
4097                        device_printf(dev, "%s: count %d\n", __func__, count);
4098
4099                        err = 0;
4100                }
4101        }
4102
4103        if (err) {
4104                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
4105                return(-1);
4106        }
4107
4108        return (0);
4109}
4110
4111static int
4112qla_get_minidump_tmplt_size(qla_host_t *ha, uint32_t *size)
4113{
4114	uint32_t			err;
4115	device_t			dev = ha->pci_dev;
4116	q80_config_md_templ_size_t	*md_size;
4117	q80_config_md_templ_size_rsp_t	*md_size_rsp;
4118
4119#ifndef QL_LDFLASH_FW
4120
4121	ql_minidump_template_hdr_t *hdr;
4122
4123	hdr = (ql_minidump_template_hdr_t *)ql83xx_minidump;
4124	*size = hdr->size_of_template;
4125	return (0);
4126
4127#endif /* #ifdef QL_LDFLASH_FW */
4128
4129	md_size = (q80_config_md_templ_size_t *) ha->hw.mbox;
4130	bzero(md_size, sizeof(q80_config_md_templ_size_t));
4131
4132	md_size->opcode = Q8_MBX_GET_MINIDUMP_TMPLT_SIZE;
4133	md_size->count_version = (sizeof (q80_config_md_templ_size_t) >> 2);
4134	md_size->count_version |= Q8_MBX_CMD_VERSION;
4135
4136	if (qla_mbx_cmd(ha, (uint32_t *) md_size,
4137		(sizeof(q80_config_md_templ_size_t) >> 2), ha->hw.mbox,
4138		(sizeof(q80_config_md_templ_size_rsp_t) >> 2), 0)) {
4139		device_printf(dev, "%s: failed\n", __func__);
4140
4141		return (-1);
4142	}
4143
4144	md_size_rsp = (q80_config_md_templ_size_rsp_t *) ha->hw.mbox;
4145
4146	err = Q8_MBX_RSP_STATUS(md_size_rsp->regcnt_status);
4147
4148        if (err) {
4149		device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
4150		return(-1);
4151        }
4152
4153	*size = md_size_rsp->templ_size;
4154
4155	return (0);
4156}
4157
4158static int
4159qla_get_port_config(qla_host_t *ha, uint32_t *cfg_bits)
4160{
4161        device_t                dev;
4162        q80_get_port_cfg_t      *pcfg;
4163        q80_get_port_cfg_rsp_t  *pcfg_rsp;
4164        uint32_t                err;
4165
4166        dev = ha->pci_dev;
4167
4168        pcfg = (q80_get_port_cfg_t *)ha->hw.mbox;
4169        bzero(pcfg, sizeof(q80_get_port_cfg_t));
4170
4171        pcfg->opcode = Q8_MBX_GET_PORT_CONFIG;
4172        pcfg->count_version = (sizeof (q80_get_port_cfg_t) >> 2);
4173        pcfg->count_version |= Q8_MBX_CMD_VERSION;
4174
4175        if (qla_mbx_cmd(ha, (uint32_t *)pcfg,
4176                (sizeof (q80_get_port_cfg_t) >> 2),
4177                ha->hw.mbox, (sizeof (q80_get_port_cfg_rsp_t) >> 2), 0)) {
4178                device_printf(dev, "%s: failed\n", __func__);
4179                return -1;
4180        }
4181
4182        pcfg_rsp = (q80_get_port_cfg_rsp_t *)ha->hw.mbox;
4183
4184        err = Q8_MBX_RSP_STATUS(pcfg_rsp->regcnt_status);
4185
4186        if (err) {
4187                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
4188                return(-1);
4189        }
4190
4191        device_printf(dev, "%s: [cfg_bits, port type]"
4192                " [0x%08x, 0x%02x] [STD_PAUSE_DIR, PAUSE_TYPE, DCBX]"
4193                " [0x%x, 0x%x, 0x%x]\n", __func__,
4194                pcfg_rsp->cfg_bits, pcfg_rsp->phys_port_type,
4195                ((pcfg_rsp->cfg_bits & Q8_PORT_CFG_BITS_STDPAUSE_DIR_MASK)>>20),
4196                ((pcfg_rsp->cfg_bits & Q8_PORT_CFG_BITS_PAUSE_CFG_MASK) >> 5),
4197                ((pcfg_rsp->cfg_bits & Q8_PORT_CFG_BITS_DCBX_ENABLE) ? 1: 0)
4198                );
4199
4200        *cfg_bits = pcfg_rsp->cfg_bits;
4201
4202        return (0);
4203}
4204
4205int
4206ql_iscsi_pdu(qla_host_t *ha, struct mbuf *mp)
4207{
4208        struct ether_vlan_header        *eh;
4209        uint16_t                        etype;
4210        struct ip                       *ip = NULL;
4211        struct ip6_hdr                  *ip6 = NULL;
4212        struct tcphdr                   *th = NULL;
4213        uint32_t                        hdrlen;
4214        uint32_t                        offset;
4215        uint8_t                         buf[sizeof(struct ip6_hdr)];
4216
4217        eh = mtod(mp, struct ether_vlan_header *);
4218
4219        if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
4220                hdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
4221                etype = ntohs(eh->evl_proto);
4222        } else {
4223                hdrlen = ETHER_HDR_LEN;
4224                etype = ntohs(eh->evl_encap_proto);
4225        }
4226
4227	if (etype == ETHERTYPE_IP) {
4228		offset = (hdrlen + sizeof (struct ip));
4229
4230		if (mp->m_len >= offset) {
4231                        ip = (struct ip *)(mp->m_data + hdrlen);
4232		} else {
4233			m_copydata(mp, hdrlen, sizeof (struct ip), buf);
4234                        ip = (struct ip *)buf;
4235		}
4236
4237                if (ip->ip_p == IPPROTO_TCP) {
4238			hdrlen += ip->ip_hl << 2;
4239			offset = hdrlen + 4;
4240
4241			if (mp->m_len >= offset) {
4242				th = (struct tcphdr *)(mp->m_data + hdrlen);
4243			} else {
4244                                m_copydata(mp, hdrlen, 4, buf);
4245				th = (struct tcphdr *)buf;
4246			}
4247                }
4248
4249	} else if (etype == ETHERTYPE_IPV6) {
4250		offset = (hdrlen + sizeof (struct ip6_hdr));
4251
4252		if (mp->m_len >= offset) {
4253                        ip6 = (struct ip6_hdr *)(mp->m_data + hdrlen);
4254		} else {
4255                        m_copydata(mp, hdrlen, sizeof (struct ip6_hdr), buf);
4256                        ip6 = (struct ip6_hdr *)buf;
4257		}
4258
4259                if (ip6->ip6_nxt == IPPROTO_TCP) {
4260			hdrlen += sizeof(struct ip6_hdr);
4261			offset = hdrlen + 4;
4262
4263			if (mp->m_len >= offset) {
4264				th = (struct tcphdr *)(mp->m_data + hdrlen);
4265			} else {
4266				m_copydata(mp, hdrlen, 4, buf);
4267				th = (struct tcphdr *)buf;
4268			}
4269                }
4270	}
4271
4272        if (th != NULL) {
4273                if ((th->th_sport == htons(3260)) ||
4274                        (th->th_dport == htons(3260)))
4275                        return 0;
4276        }
4277        return (-1);
4278}
4279
4280void
4281qla_hw_async_event(qla_host_t *ha)
4282{
4283        switch (ha->hw.aen_mb0) {
4284        case 0x8101:
4285                (void)qla_idc_ack(ha, ha->hw.aen_mb1, ha->hw.aen_mb2,
4286                        ha->hw.aen_mb3, ha->hw.aen_mb4);
4287
4288                break;
4289
4290        default:
4291                break;
4292        }
4293
4294        return;
4295}
4296
4297#ifdef QL_LDFLASH_FW
4298static int
4299ql_get_minidump_template(qla_host_t *ha)
4300{
4301	uint32_t			err;
4302	device_t			dev = ha->pci_dev;
4303	q80_config_md_templ_cmd_t	*md_templ;
4304	q80_config_md_templ_cmd_rsp_t	*md_templ_rsp;
4305
4306	md_templ = (q80_config_md_templ_cmd_t *) ha->hw.mbox;
4307	bzero(md_templ, (sizeof (q80_config_md_templ_cmd_t)));
4308
4309	md_templ->opcode = Q8_MBX_GET_MINIDUMP_TMPLT;
4310	md_templ->count_version = ( sizeof(q80_config_md_templ_cmd_t) >> 2);
4311	md_templ->count_version |= Q8_MBX_CMD_VERSION;
4312
4313	md_templ->buf_addr = ha->hw.dma_buf.minidump.dma_addr;
4314	md_templ->buff_size = ha->hw.dma_buf.minidump.size;
4315
4316	if (qla_mbx_cmd(ha, (uint32_t *) md_templ,
4317		(sizeof(q80_config_md_templ_cmd_t) >> 2),
4318		 ha->hw.mbox,
4319		(sizeof(q80_config_md_templ_cmd_rsp_t) >> 2), 0)) {
4320		device_printf(dev, "%s: failed\n", __func__);
4321
4322		return (-1);
4323	}
4324
4325	md_templ_rsp = (q80_config_md_templ_cmd_rsp_t *) ha->hw.mbox;
4326
4327	err = Q8_MBX_RSP_STATUS(md_templ_rsp->regcnt_status);
4328
4329	if (err) {
4330		device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
4331		return (-1);
4332	}
4333
4334	return (0);
4335
4336}
4337#endif /* #ifdef QL_LDFLASH_FW */
4338
4339/*
4340 * Minidump related functionality
4341 */
4342
4343static int ql_parse_template(qla_host_t *ha);
4344
4345static uint32_t ql_rdcrb(qla_host_t *ha,
4346			ql_minidump_entry_rdcrb_t *crb_entry,
4347			uint32_t * data_buff);
4348
4349static uint32_t ql_pollrd(qla_host_t *ha,
4350			ql_minidump_entry_pollrd_t *entry,
4351			uint32_t * data_buff);
4352
4353static uint32_t ql_pollrd_modify_write(qla_host_t *ha,
4354			ql_minidump_entry_rd_modify_wr_with_poll_t *entry,
4355			uint32_t *data_buff);
4356
4357static uint32_t ql_L2Cache(qla_host_t *ha,
4358			ql_minidump_entry_cache_t *cacheEntry,
4359			uint32_t * data_buff);
4360
4361static uint32_t ql_L1Cache(qla_host_t *ha,
4362			ql_minidump_entry_cache_t *cacheEntry,
4363			uint32_t *data_buff);
4364
4365static uint32_t ql_rdocm(qla_host_t *ha,
4366			ql_minidump_entry_rdocm_t *ocmEntry,
4367			uint32_t *data_buff);
4368
4369static uint32_t ql_rdmem(qla_host_t *ha,
4370			ql_minidump_entry_rdmem_t *mem_entry,
4371			uint32_t *data_buff);
4372
4373static uint32_t ql_rdrom(qla_host_t *ha,
4374			ql_minidump_entry_rdrom_t *romEntry,
4375			uint32_t *data_buff);
4376
4377static uint32_t ql_rdmux(qla_host_t *ha,
4378			ql_minidump_entry_mux_t *muxEntry,
4379			uint32_t *data_buff);
4380
4381static uint32_t ql_rdmux2(qla_host_t *ha,
4382			ql_minidump_entry_mux2_t *muxEntry,
4383			uint32_t *data_buff);
4384
4385static uint32_t ql_rdqueue(qla_host_t *ha,
4386			ql_minidump_entry_queue_t *queueEntry,
4387			uint32_t *data_buff);
4388
4389static uint32_t ql_cntrl(qla_host_t *ha,
4390			ql_minidump_template_hdr_t *template_hdr,
4391			ql_minidump_entry_cntrl_t *crbEntry);
4392
4393static uint32_t
4394ql_minidump_size(qla_host_t *ha)
4395{
4396	uint32_t i, k;
4397	uint32_t size = 0;
4398	ql_minidump_template_hdr_t *hdr;
4399
4400	hdr = (ql_minidump_template_hdr_t *)ha->hw.dma_buf.minidump.dma_b;
4401
4402	i = 0x2;
4403
4404	for (k = 1; k < QL_DBG_CAP_SIZE_ARRAY_LEN; k++) {
4405		if (i & ha->hw.mdump_capture_mask)
4406			size += hdr->capture_size_array[k];
4407		i = i << 1;
4408	}
4409	return (size);
4410}
4411
4412static void
4413ql_free_minidump_buffer(qla_host_t *ha)
4414{
4415	if (ha->hw.mdump_buffer != NULL) {
4416		free(ha->hw.mdump_buffer, M_QLA83XXBUF);
4417		ha->hw.mdump_buffer = NULL;
4418		ha->hw.mdump_buffer_size = 0;
4419	}
4420	return;
4421}
4422
4423static int
4424ql_alloc_minidump_buffer(qla_host_t *ha)
4425{
4426	ha->hw.mdump_buffer_size = ql_minidump_size(ha);
4427
4428	if (!ha->hw.mdump_buffer_size)
4429		return (-1);
4430
4431	ha->hw.mdump_buffer = malloc(ha->hw.mdump_buffer_size, M_QLA83XXBUF,
4432					M_NOWAIT);
4433
4434	if (ha->hw.mdump_buffer == NULL)
4435		return (-1);
4436
4437	return (0);
4438}
4439
4440static void
4441ql_free_minidump_template_buffer(qla_host_t *ha)
4442{
4443	if (ha->hw.mdump_template != NULL) {
4444		free(ha->hw.mdump_template, M_QLA83XXBUF);
4445		ha->hw.mdump_template = NULL;
4446		ha->hw.mdump_template_size = 0;
4447	}
4448	return;
4449}
4450
4451static int
4452ql_alloc_minidump_template_buffer(qla_host_t *ha)
4453{
4454	ha->hw.mdump_template_size = ha->hw.dma_buf.minidump.size;
4455
4456	ha->hw.mdump_template = malloc(ha->hw.mdump_template_size,
4457					M_QLA83XXBUF, M_NOWAIT);
4458
4459	if (ha->hw.mdump_template == NULL)
4460		return (-1);
4461
4462	return (0);
4463}
4464
4465static int
4466ql_alloc_minidump_buffers(qla_host_t *ha)
4467{
4468	int ret;
4469
4470	ret = ql_alloc_minidump_template_buffer(ha);
4471
4472	if (ret)
4473		return (ret);
4474
4475	ret = ql_alloc_minidump_buffer(ha);
4476
4477	if (ret)
4478		ql_free_minidump_template_buffer(ha);
4479
4480	return (ret);
4481}
4482
4483static uint32_t
4484ql_validate_minidump_checksum(qla_host_t *ha)
4485{
4486        uint64_t sum = 0;
4487	int count;
4488	uint32_t *template_buff;
4489
4490	count = ha->hw.dma_buf.minidump.size / sizeof (uint32_t);
4491	template_buff = ha->hw.dma_buf.minidump.dma_b;
4492
4493	while (count-- > 0) {
4494		sum += *template_buff++;
4495	}
4496
4497	while (sum >> 32) {
4498		sum = (sum & 0xFFFFFFFF) + (sum >> 32);
4499	}
4500
4501	return (~sum);
4502}
4503
4504int
4505ql_minidump_init(qla_host_t *ha)
4506{
4507	int		ret = 0;
4508	uint32_t	template_size = 0;
4509	device_t	dev = ha->pci_dev;
4510
4511	/*
4512	 * Get Minidump Template Size
4513 	 */
4514	ret = qla_get_minidump_tmplt_size(ha, &template_size);
4515
4516	if (ret || (template_size == 0)) {
4517		device_printf(dev, "%s: failed [%d, %d]\n", __func__, ret,
4518			template_size);
4519		return (-1);
4520	}
4521
4522	/*
4523	 * Allocate Memory for Minidump Template
4524	 */
4525
4526	ha->hw.dma_buf.minidump.alignment = 8;
4527	ha->hw.dma_buf.minidump.size = template_size;
4528
4529#ifdef QL_LDFLASH_FW
4530	if (ql_alloc_dmabuf(ha, &ha->hw.dma_buf.minidump)) {
4531		device_printf(dev, "%s: minidump dma alloc failed\n", __func__);
4532
4533		return (-1);
4534	}
4535	ha->hw.dma_buf.flags.minidump = 1;
4536
4537	/*
4538	 * Retrieve Minidump Template
4539	 */
4540	ret = ql_get_minidump_template(ha);
4541#else
4542	ha->hw.dma_buf.minidump.dma_b = ql83xx_minidump;
4543
4544#endif /* #ifdef QL_LDFLASH_FW */
4545
4546	if (ret == 0) {
4547		ret = ql_validate_minidump_checksum(ha);
4548
4549		if (ret == 0) {
4550			ret = ql_alloc_minidump_buffers(ha);
4551
4552			if (ret == 0)
4553		ha->hw.mdump_init = 1;
4554			else
4555				device_printf(dev,
4556					"%s: ql_alloc_minidump_buffers"
4557					" failed\n", __func__);
4558		} else {
4559			device_printf(dev, "%s: ql_validate_minidump_checksum"
4560				" failed\n", __func__);
4561		}
4562	} else {
4563		device_printf(dev, "%s: ql_get_minidump_template failed\n",
4564			 __func__);
4565	}
4566
4567	if (ret)
4568		ql_minidump_free(ha);
4569
4570	return (ret);
4571}
4572
4573static void
4574ql_minidump_free(qla_host_t *ha)
4575{
4576	ha->hw.mdump_init = 0;
4577	if (ha->hw.dma_buf.flags.minidump) {
4578		ha->hw.dma_buf.flags.minidump = 0;
4579		ql_free_dmabuf(ha, &ha->hw.dma_buf.minidump);
4580	}
4581
4582	ql_free_minidump_template_buffer(ha);
4583	ql_free_minidump_buffer(ha);
4584
4585	return;
4586}
4587
4588void
4589ql_minidump(qla_host_t *ha)
4590{
4591	if (!ha->hw.mdump_init)
4592		return;
4593
4594	if (ha->hw.mdump_done)
4595		return;
4596	ha->hw.mdump_usec_ts = qla_get_usec_timestamp();
4597	ha->hw.mdump_start_seq_index = ql_stop_sequence(ha);
4598
4599	bzero(ha->hw.mdump_buffer, ha->hw.mdump_buffer_size);
4600	bzero(ha->hw.mdump_template, ha->hw.mdump_template_size);
4601
4602	bcopy(ha->hw.dma_buf.minidump.dma_b, ha->hw.mdump_template,
4603		ha->hw.mdump_template_size);
4604
4605	ql_parse_template(ha);
4606
4607	ql_start_sequence(ha, ha->hw.mdump_start_seq_index);
4608
4609	ha->hw.mdump_done = 1;
4610
4611	return;
4612}
4613
4614/*
4615 * helper routines
4616 */
4617static void
4618ql_entry_err_chk(ql_minidump_entry_t *entry, uint32_t esize)
4619{
4620	if (esize != entry->hdr.entry_capture_size) {
4621		entry->hdr.entry_capture_size = esize;
4622		entry->hdr.driver_flags |= QL_DBG_SIZE_ERR_FLAG;
4623	}
4624	return;
4625}
4626
4627static int
4628ql_parse_template(qla_host_t *ha)
4629{
4630	uint32_t num_of_entries, buff_level, e_cnt, esize;
4631	uint32_t rv = 0;
4632	char *dump_buff, *dbuff;
4633	int sane_start = 0, sane_end = 0;
4634	ql_minidump_template_hdr_t *template_hdr;
4635	ql_minidump_entry_t *entry;
4636	uint32_t capture_mask;
4637	uint32_t dump_size;
4638
4639	/* Setup parameters */
4640	template_hdr = (ql_minidump_template_hdr_t *)ha->hw.mdump_template;
4641
4642	if (template_hdr->entry_type == TLHDR)
4643		sane_start = 1;
4644
4645	dump_buff = (char *) ha->hw.mdump_buffer;
4646
4647	num_of_entries = template_hdr->num_of_entries;
4648
4649	entry = (ql_minidump_entry_t *) ((char *)template_hdr
4650			+ template_hdr->first_entry_offset );
4651
4652	template_hdr->saved_state_array[QL_OCM0_ADDR_INDX] =
4653		template_hdr->ocm_window_array[ha->pci_func];
4654	template_hdr->saved_state_array[QL_PCIE_FUNC_INDX] = ha->pci_func;
4655
4656	capture_mask = ha->hw.mdump_capture_mask;
4657	dump_size = ha->hw.mdump_buffer_size;
4658
4659	template_hdr->driver_capture_mask = capture_mask;
4660
4661	QL_DPRINT80(ha, (ha->pci_dev,
4662		"%s: sane_start = %d num_of_entries = %d "
4663		"capture_mask = 0x%x dump_size = %d \n",
4664		__func__, sane_start, num_of_entries, capture_mask, dump_size));
4665
4666	for (buff_level = 0, e_cnt = 0; e_cnt < num_of_entries; e_cnt++) {
4667		/*
4668		 * If the capture_mask of the entry does not match capture mask
4669		 * skip the entry after marking the driver_flags indicator.
4670		 */
4671
4672		if (!(entry->hdr.entry_capture_mask & capture_mask)) {
4673			entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG;
4674			entry = (ql_minidump_entry_t *) ((char *) entry
4675					+ entry->hdr.entry_size);
4676			continue;
4677		}
4678
4679		/*
4680		 * This is ONLY needed in implementations where
4681		 * the capture buffer allocated is too small to capture
4682		 * all of the required entries for a given capture mask.
4683		 * We need to empty the buffer contents to a file
4684		 * if possible, before processing the next entry
4685		 * If the buff_full_flag is set, no further capture will happen
4686		 * and all remaining non-control entries will be skipped.
4687		 */
4688		if (entry->hdr.entry_capture_size != 0) {
4689			if ((buff_level + entry->hdr.entry_capture_size) >
4690				dump_size) {
4691				/*  Try to recover by emptying buffer to file */
4692				entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG;
4693				entry = (ql_minidump_entry_t *) ((char *) entry
4694						+ entry->hdr.entry_size);
4695				continue;
4696			}
4697		}
4698
4699		/*
4700		 * Decode the entry type and process it accordingly
4701		 */
4702
4703		switch (entry->hdr.entry_type) {
4704		case RDNOP:
4705			break;
4706
4707		case RDEND:
4708			sane_end++;
4709			break;
4710
4711		case RDCRB:
4712			dbuff = dump_buff + buff_level;
4713			esize = ql_rdcrb(ha, (void *)entry, (void *)dbuff);
4714			ql_entry_err_chk(entry, esize);
4715			buff_level += esize;
4716			break;
4717
4718                case POLLRD:
4719                        dbuff = dump_buff + buff_level;
4720                        esize = ql_pollrd(ha, (void *)entry, (void *)dbuff);
4721                        ql_entry_err_chk(entry, esize);
4722                        buff_level += esize;
4723                        break;
4724
4725                case POLLRDMWR:
4726                        dbuff = dump_buff + buff_level;
4727                        esize = ql_pollrd_modify_write(ha, (void *)entry,
4728					(void *)dbuff);
4729                        ql_entry_err_chk(entry, esize);
4730                        buff_level += esize;
4731                        break;
4732
4733		case L2ITG:
4734		case L2DTG:
4735		case L2DAT:
4736		case L2INS:
4737			dbuff = dump_buff + buff_level;
4738			esize = ql_L2Cache(ha, (void *)entry, (void *)dbuff);
4739			if (esize == -1) {
4740				entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG;
4741			} else {
4742				ql_entry_err_chk(entry, esize);
4743				buff_level += esize;
4744			}
4745			break;
4746
4747		case L1DAT:
4748		case L1INS:
4749			dbuff = dump_buff + buff_level;
4750			esize = ql_L1Cache(ha, (void *)entry, (void *)dbuff);
4751			ql_entry_err_chk(entry, esize);
4752			buff_level += esize;
4753			break;
4754
4755		case RDOCM:
4756			dbuff = dump_buff + buff_level;
4757			esize = ql_rdocm(ha, (void *)entry, (void *)dbuff);
4758			ql_entry_err_chk(entry, esize);
4759			buff_level += esize;
4760			break;
4761
4762		case RDMEM:
4763			dbuff = dump_buff + buff_level;
4764			esize = ql_rdmem(ha, (void *)entry, (void *)dbuff);
4765			ql_entry_err_chk(entry, esize);
4766			buff_level += esize;
4767			break;
4768
4769		case BOARD:
4770		case RDROM:
4771			dbuff = dump_buff + buff_level;
4772			esize = ql_rdrom(ha, (void *)entry, (void *)dbuff);
4773			ql_entry_err_chk(entry, esize);
4774			buff_level += esize;
4775			break;
4776
4777		case RDMUX:
4778			dbuff = dump_buff + buff_level;
4779			esize = ql_rdmux(ha, (void *)entry, (void *)dbuff);
4780			ql_entry_err_chk(entry, esize);
4781			buff_level += esize;
4782			break;
4783
4784                case RDMUX2:
4785                        dbuff = dump_buff + buff_level;
4786                        esize = ql_rdmux2(ha, (void *)entry, (void *)dbuff);
4787                        ql_entry_err_chk(entry, esize);
4788                        buff_level += esize;
4789                        break;
4790
4791		case QUEUE:
4792			dbuff = dump_buff + buff_level;
4793			esize = ql_rdqueue(ha, (void *)entry, (void *)dbuff);
4794			ql_entry_err_chk(entry, esize);
4795			buff_level += esize;
4796			break;
4797
4798		case CNTRL:
4799			if ((rv = ql_cntrl(ha, template_hdr, (void *)entry))) {
4800				entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG;
4801			}
4802			break;
4803		default:
4804			entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG;
4805			break;
4806		}
4807		/*  next entry in the template */
4808		entry = (ql_minidump_entry_t *) ((char *) entry
4809						+ entry->hdr.entry_size);
4810	}
4811
4812	if (!sane_start || (sane_end > 1)) {
4813		device_printf(ha->pci_dev,
4814			"\n%s: Template configuration error. Check Template\n",
4815			__func__);
4816	}
4817
4818	QL_DPRINT80(ha, (ha->pci_dev, "%s: Minidump num of entries = %d\n",
4819		__func__, template_hdr->num_of_entries));
4820
4821	return 0;
4822}
4823
4824/*
4825 * Read CRB operation.
4826 */
4827static uint32_t
4828ql_rdcrb(qla_host_t *ha, ql_minidump_entry_rdcrb_t * crb_entry,
4829	uint32_t * data_buff)
4830{
4831	int loop_cnt;
4832	int ret;
4833	uint32_t op_count, addr, stride, value = 0;
4834
4835	addr = crb_entry->addr;
4836	op_count = crb_entry->op_count;
4837	stride = crb_entry->addr_stride;
4838
4839	for (loop_cnt = 0; loop_cnt < op_count; loop_cnt++) {
4840		ret = ql_rdwr_indreg32(ha, addr, &value, 1);
4841
4842		if (ret)
4843			return (0);
4844
4845		*data_buff++ = addr;
4846		*data_buff++ = value;
4847		addr = addr + stride;
4848	}
4849
4850	/*
4851	 * for testing purpose we return amount of data written
4852	 */
4853	return (op_count * (2 * sizeof(uint32_t)));
4854}
4855
4856/*
4857 * Handle L2 Cache.
4858 */
4859
4860static uint32_t
4861ql_L2Cache(qla_host_t *ha, ql_minidump_entry_cache_t *cacheEntry,
4862	uint32_t * data_buff)
4863{
4864	int i, k;
4865	int loop_cnt;
4866	int ret;
4867
4868	uint32_t read_value;
4869	uint32_t addr, read_addr, cntrl_addr, tag_reg_addr, cntl_value_w;
4870	uint32_t tag_value, read_cnt;
4871	volatile uint8_t cntl_value_r;
4872	long timeout;
4873	uint32_t data;
4874
4875	loop_cnt = cacheEntry->op_count;
4876
4877	read_addr = cacheEntry->read_addr;
4878	cntrl_addr = cacheEntry->control_addr;
4879	cntl_value_w = (uint32_t) cacheEntry->write_value;
4880
4881	tag_reg_addr = cacheEntry->tag_reg_addr;
4882
4883	tag_value = cacheEntry->init_tag_value;
4884	read_cnt = cacheEntry->read_addr_cnt;
4885
4886	for (i = 0; i < loop_cnt; i++) {
4887		ret = ql_rdwr_indreg32(ha, tag_reg_addr, &tag_value, 0);
4888		if (ret)
4889			return (0);
4890
4891		if (cacheEntry->write_value != 0) {
4892
4893			ret = ql_rdwr_indreg32(ha, cntrl_addr,
4894					&cntl_value_w, 0);
4895			if (ret)
4896				return (0);
4897		}
4898
4899		if (cacheEntry->poll_mask != 0) {
4900
4901			timeout = cacheEntry->poll_wait;
4902
4903			ret = ql_rdwr_indreg32(ha, cntrl_addr, &data, 1);
4904			if (ret)
4905				return (0);
4906
4907			cntl_value_r = (uint8_t)data;
4908
4909			while ((cntl_value_r & cacheEntry->poll_mask) != 0) {
4910				if (timeout) {
4911					qla_mdelay(__func__, 1);
4912					timeout--;
4913				} else
4914					break;
4915
4916				ret = ql_rdwr_indreg32(ha, cntrl_addr,
4917						&data, 1);
4918				if (ret)
4919					return (0);
4920
4921				cntl_value_r = (uint8_t)data;
4922			}
4923			if (!timeout) {
4924				/* Report timeout error.
4925				 * core dump capture failed
4926				 * Skip remaining entries.
4927				 * Write buffer out to file
4928				 * Use driver specific fields in template header
4929				 * to report this error.
4930				 */
4931				return (-1);
4932			}
4933		}
4934
4935		addr = read_addr;
4936		for (k = 0; k < read_cnt; k++) {
4937			ret = ql_rdwr_indreg32(ha, addr, &read_value, 1);
4938			if (ret)
4939				return (0);
4940
4941			*data_buff++ = read_value;
4942			addr += cacheEntry->read_addr_stride;
4943		}
4944
4945		tag_value += cacheEntry->tag_value_stride;
4946	}
4947
4948	return (read_cnt * loop_cnt * sizeof(uint32_t));
4949}
4950
4951/*
4952 * Handle L1 Cache.
4953 */
4954
4955static uint32_t
4956ql_L1Cache(qla_host_t *ha,
4957	ql_minidump_entry_cache_t *cacheEntry,
4958	uint32_t *data_buff)
4959{
4960	int ret;
4961	int i, k;
4962	int loop_cnt;
4963
4964	uint32_t read_value;
4965	uint32_t addr, read_addr, cntrl_addr, tag_reg_addr;
4966	uint32_t tag_value, read_cnt;
4967	uint32_t cntl_value_w;
4968
4969	loop_cnt = cacheEntry->op_count;
4970
4971	read_addr = cacheEntry->read_addr;
4972	cntrl_addr = cacheEntry->control_addr;
4973	cntl_value_w = (uint32_t) cacheEntry->write_value;
4974
4975	tag_reg_addr = cacheEntry->tag_reg_addr;
4976
4977	tag_value = cacheEntry->init_tag_value;
4978	read_cnt = cacheEntry->read_addr_cnt;
4979
4980	for (i = 0; i < loop_cnt; i++) {
4981		ret = ql_rdwr_indreg32(ha, tag_reg_addr, &tag_value, 0);
4982		if (ret)
4983			return (0);
4984
4985		ret = ql_rdwr_indreg32(ha, cntrl_addr, &cntl_value_w, 0);
4986		if (ret)
4987			return (0);
4988
4989		addr = read_addr;
4990		for (k = 0; k < read_cnt; k++) {
4991			ret = ql_rdwr_indreg32(ha, addr, &read_value, 1);
4992			if (ret)
4993				return (0);
4994
4995			*data_buff++ = read_value;
4996			addr += cacheEntry->read_addr_stride;
4997		}
4998
4999		tag_value += cacheEntry->tag_value_stride;
5000	}
5001
5002	return (read_cnt * loop_cnt * sizeof(uint32_t));
5003}
5004
5005/*
5006 * Reading OCM memory
5007 */
5008
5009static uint32_t
5010ql_rdocm(qla_host_t *ha,
5011	ql_minidump_entry_rdocm_t *ocmEntry,
5012	uint32_t *data_buff)
5013{
5014	int i, loop_cnt;
5015	volatile uint32_t addr;
5016	volatile uint32_t value;
5017
5018	addr = ocmEntry->read_addr;
5019	loop_cnt = ocmEntry->op_count;
5020
5021	for (i = 0; i < loop_cnt; i++) {
5022		value = READ_REG32(ha, addr);
5023		*data_buff++ = value;
5024		addr += ocmEntry->read_addr_stride;
5025	}
5026	return (loop_cnt * sizeof(value));
5027}
5028
5029/*
5030 * Read memory
5031 */
5032
5033static uint32_t
5034ql_rdmem(qla_host_t *ha,
5035	ql_minidump_entry_rdmem_t *mem_entry,
5036	uint32_t *data_buff)
5037{
5038	int ret;
5039        int i, loop_cnt;
5040        volatile uint32_t addr;
5041	q80_offchip_mem_val_t val;
5042
5043        addr = mem_entry->read_addr;
5044
5045	/* size in bytes / 16 */
5046        loop_cnt = mem_entry->read_data_size / (sizeof(uint32_t) * 4);
5047
5048        for (i = 0; i < loop_cnt; i++) {
5049		ret = ql_rdwr_offchip_mem(ha, (addr & 0x0ffffffff), &val, 1);
5050		if (ret)
5051			return (0);
5052
5053                *data_buff++ = val.data_lo;
5054                *data_buff++ = val.data_hi;
5055                *data_buff++ = val.data_ulo;
5056                *data_buff++ = val.data_uhi;
5057
5058                addr += (sizeof(uint32_t) * 4);
5059        }
5060
5061        return (loop_cnt * (sizeof(uint32_t) * 4));
5062}
5063
5064/*
5065 * Read Rom
5066 */
5067
5068static uint32_t
5069ql_rdrom(qla_host_t *ha,
5070	ql_minidump_entry_rdrom_t *romEntry,
5071	uint32_t *data_buff)
5072{
5073	int ret;
5074	int i, loop_cnt;
5075	uint32_t addr;
5076	uint32_t value;
5077
5078	addr = romEntry->read_addr;
5079	loop_cnt = romEntry->read_data_size; /* This is size in bytes */
5080	loop_cnt /= sizeof(value);
5081
5082	for (i = 0; i < loop_cnt; i++) {
5083		ret = ql_rd_flash32(ha, addr, &value);
5084		if (ret)
5085			return (0);
5086
5087		*data_buff++ = value;
5088		addr += sizeof(value);
5089	}
5090
5091	return (loop_cnt * sizeof(value));
5092}
5093
5094/*
5095 * Read MUX data
5096 */
5097
5098static uint32_t
5099ql_rdmux(qla_host_t *ha,
5100	ql_minidump_entry_mux_t *muxEntry,
5101	uint32_t *data_buff)
5102{
5103	int ret;
5104	int loop_cnt;
5105	uint32_t read_value, sel_value;
5106	uint32_t read_addr, select_addr;
5107
5108	select_addr = muxEntry->select_addr;
5109	sel_value = muxEntry->select_value;
5110	read_addr = muxEntry->read_addr;
5111
5112	for (loop_cnt = 0; loop_cnt < muxEntry->op_count; loop_cnt++) {
5113		ret = ql_rdwr_indreg32(ha, select_addr, &sel_value, 0);
5114		if (ret)
5115			return (0);
5116
5117		ret = ql_rdwr_indreg32(ha, read_addr, &read_value, 1);
5118		if (ret)
5119			return (0);
5120
5121		*data_buff++ = sel_value;
5122		*data_buff++ = read_value;
5123
5124		sel_value += muxEntry->select_value_stride;
5125	}
5126
5127	return (loop_cnt * (2 * sizeof(uint32_t)));
5128}
5129
5130static uint32_t
5131ql_rdmux2(qla_host_t *ha,
5132	ql_minidump_entry_mux2_t *muxEntry,
5133	uint32_t *data_buff)
5134{
5135	int ret;
5136        int loop_cnt;
5137
5138        uint32_t select_addr_1, select_addr_2;
5139        uint32_t select_value_1, select_value_2;
5140        uint32_t select_value_count, select_value_mask;
5141        uint32_t read_addr, read_value;
5142
5143        select_addr_1 = muxEntry->select_addr_1;
5144        select_addr_2 = muxEntry->select_addr_2;
5145        select_value_1 = muxEntry->select_value_1;
5146        select_value_2 = muxEntry->select_value_2;
5147        select_value_count = muxEntry->select_value_count;
5148        select_value_mask  = muxEntry->select_value_mask;
5149
5150        read_addr = muxEntry->read_addr;
5151
5152        for (loop_cnt = 0; loop_cnt < select_value_count; loop_cnt++) {
5153                uint32_t temp_sel_val;
5154
5155		ret = ql_rdwr_indreg32(ha, select_addr_1, &select_value_1, 0);
5156		if (ret)
5157			return (0);
5158
5159                temp_sel_val = select_value_1 & select_value_mask;
5160
5161		ret = ql_rdwr_indreg32(ha, select_addr_2, &temp_sel_val, 0);
5162		if (ret)
5163			return (0);
5164
5165		ret = ql_rdwr_indreg32(ha, read_addr, &read_value, 1);
5166		if (ret)
5167			return (0);
5168
5169                *data_buff++ = temp_sel_val;
5170                *data_buff++ = read_value;
5171
5172		ret = ql_rdwr_indreg32(ha, select_addr_1, &select_value_2, 0);
5173		if (ret)
5174			return (0);
5175
5176                temp_sel_val = select_value_2 & select_value_mask;
5177
5178		ret = ql_rdwr_indreg32(ha, select_addr_2, &temp_sel_val, 0);
5179		if (ret)
5180			return (0);
5181
5182		ret = ql_rdwr_indreg32(ha, read_addr, &read_value, 1);
5183		if (ret)
5184			return (0);
5185
5186                *data_buff++ = temp_sel_val;
5187                *data_buff++ = read_value;
5188
5189                select_value_1 += muxEntry->select_value_stride;
5190                select_value_2 += muxEntry->select_value_stride;
5191        }
5192
5193        return (loop_cnt * (4 * sizeof(uint32_t)));
5194}
5195
5196/*
5197 * Handling Queue State Reads.
5198 */
5199
5200static uint32_t
5201ql_rdqueue(qla_host_t *ha,
5202	ql_minidump_entry_queue_t *queueEntry,
5203	uint32_t *data_buff)
5204{
5205	int ret;
5206	int loop_cnt, k;
5207	uint32_t read_value;
5208	uint32_t read_addr, read_stride, select_addr;
5209	uint32_t queue_id, read_cnt;
5210
5211	read_cnt = queueEntry->read_addr_cnt;
5212	read_stride = queueEntry->read_addr_stride;
5213	select_addr = queueEntry->select_addr;
5214
5215	for (loop_cnt = 0, queue_id = 0; loop_cnt < queueEntry->op_count;
5216		loop_cnt++) {
5217		ret = ql_rdwr_indreg32(ha, select_addr, &queue_id, 0);
5218		if (ret)
5219			return (0);
5220
5221		read_addr = queueEntry->read_addr;
5222
5223		for (k = 0; k < read_cnt; k++) {
5224			ret = ql_rdwr_indreg32(ha, read_addr, &read_value, 1);
5225			if (ret)
5226				return (0);
5227
5228			*data_buff++ = read_value;
5229			read_addr += read_stride;
5230		}
5231
5232		queue_id += queueEntry->queue_id_stride;
5233	}
5234
5235	return (loop_cnt * (read_cnt * sizeof(uint32_t)));
5236}
5237
5238/*
5239 * Handling control entries.
5240 */
5241
5242static uint32_t
5243ql_cntrl(qla_host_t *ha,
5244	ql_minidump_template_hdr_t *template_hdr,
5245	ql_minidump_entry_cntrl_t *crbEntry)
5246{
5247	int ret;
5248	int count;
5249	uint32_t opcode, read_value, addr, entry_addr;
5250	long timeout;
5251
5252	entry_addr = crbEntry->addr;
5253
5254	for (count = 0; count < crbEntry->op_count; count++) {
5255		opcode = crbEntry->opcode;
5256
5257		if (opcode & QL_DBG_OPCODE_WR) {
5258                	ret = ql_rdwr_indreg32(ha, entry_addr,
5259					&crbEntry->value_1, 0);
5260			if (ret)
5261				return (0);
5262
5263			opcode &= ~QL_DBG_OPCODE_WR;
5264		}
5265
5266		if (opcode & QL_DBG_OPCODE_RW) {
5267                	ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 1);
5268			if (ret)
5269				return (0);
5270
5271                	ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 0);
5272			if (ret)
5273				return (0);
5274
5275			opcode &= ~QL_DBG_OPCODE_RW;
5276		}
5277
5278		if (opcode & QL_DBG_OPCODE_AND) {
5279                	ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 1);
5280			if (ret)
5281				return (0);
5282
5283			read_value &= crbEntry->value_2;
5284			opcode &= ~QL_DBG_OPCODE_AND;
5285
5286			if (opcode & QL_DBG_OPCODE_OR) {
5287				read_value |= crbEntry->value_3;
5288				opcode &= ~QL_DBG_OPCODE_OR;
5289			}
5290
5291                	ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 0);
5292			if (ret)
5293				return (0);
5294		}
5295
5296		if (opcode & QL_DBG_OPCODE_OR) {
5297                	ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 1);
5298			if (ret)
5299				return (0);
5300
5301			read_value |= crbEntry->value_3;
5302
5303                	ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 0);
5304			if (ret)
5305				return (0);
5306
5307			opcode &= ~QL_DBG_OPCODE_OR;
5308		}
5309
5310		if (opcode & QL_DBG_OPCODE_POLL) {
5311			opcode &= ~QL_DBG_OPCODE_POLL;
5312			timeout = crbEntry->poll_timeout;
5313			addr = entry_addr;
5314
5315                	ret = ql_rdwr_indreg32(ha, addr, &read_value, 1);
5316			if (ret)
5317				return (0);
5318
5319			while ((read_value & crbEntry->value_2)
5320				!= crbEntry->value_1) {
5321				if (timeout) {
5322					qla_mdelay(__func__, 1);
5323					timeout--;
5324				} else
5325					break;
5326
5327                		ret = ql_rdwr_indreg32(ha, addr,
5328						&read_value, 1);
5329				if (ret)
5330					return (0);
5331			}
5332
5333			if (!timeout) {
5334				/*
5335				 * Report timeout error.
5336				 * core dump capture failed
5337				 * Skip remaining entries.
5338				 * Write buffer out to file
5339				 * Use driver specific fields in template header
5340				 * to report this error.
5341				 */
5342				return (-1);
5343			}
5344		}
5345
5346		if (opcode & QL_DBG_OPCODE_RDSTATE) {
5347			/*
5348			 * decide which address to use.
5349			 */
5350			if (crbEntry->state_index_a) {
5351				addr = template_hdr->saved_state_array[
5352						crbEntry-> state_index_a];
5353			} else {
5354				addr = entry_addr;
5355			}
5356
5357                	ret = ql_rdwr_indreg32(ha, addr, &read_value, 1);
5358			if (ret)
5359				return (0);
5360
5361			template_hdr->saved_state_array[crbEntry->state_index_v]
5362					= read_value;
5363			opcode &= ~QL_DBG_OPCODE_RDSTATE;
5364		}
5365
5366		if (opcode & QL_DBG_OPCODE_WRSTATE) {
5367			/*
5368			 * decide which value to use.
5369			 */
5370			if (crbEntry->state_index_v) {
5371				read_value = template_hdr->saved_state_array[
5372						crbEntry->state_index_v];
5373			} else {
5374				read_value = crbEntry->value_1;
5375			}
5376			/*
5377			 * decide which address to use.
5378			 */
5379			if (crbEntry->state_index_a) {
5380				addr = template_hdr->saved_state_array[
5381						crbEntry-> state_index_a];
5382			} else {
5383				addr = entry_addr;
5384			}
5385
5386                	ret = ql_rdwr_indreg32(ha, addr, &read_value, 0);
5387			if (ret)
5388				return (0);
5389
5390			opcode &= ~QL_DBG_OPCODE_WRSTATE;
5391		}
5392
5393		if (opcode & QL_DBG_OPCODE_MDSTATE) {
5394			/*  Read value from saved state using index */
5395			read_value = template_hdr->saved_state_array[
5396						crbEntry->state_index_v];
5397
5398			read_value <<= crbEntry->shl; /*Shift left operation */
5399			read_value >>= crbEntry->shr; /*Shift right operation */
5400
5401			if (crbEntry->value_2) {
5402				/* check if AND mask is provided */
5403				read_value &= crbEntry->value_2;
5404			}
5405
5406			read_value |= crbEntry->value_3; /* OR operation */
5407			read_value += crbEntry->value_1; /* increment op */
5408
5409			/* Write value back to state area. */
5410
5411			template_hdr->saved_state_array[crbEntry->state_index_v]
5412					= read_value;
5413			opcode &= ~QL_DBG_OPCODE_MDSTATE;
5414		}
5415
5416		entry_addr += crbEntry->addr_stride;
5417	}
5418
5419	return (0);
5420}
5421
5422/*
5423 * Handling rd poll entry.
5424 */
5425
5426static uint32_t
5427ql_pollrd(qla_host_t *ha, ql_minidump_entry_pollrd_t *entry,
5428	uint32_t *data_buff)
5429{
5430        int ret;
5431        int loop_cnt;
5432        uint32_t op_count, select_addr, select_value_stride, select_value;
5433        uint32_t read_addr, poll, mask, data;
5434        uint32_t wait_count = 0;
5435
5436        select_addr            = entry->select_addr;
5437        read_addr              = entry->read_addr;
5438        select_value           = entry->select_value;
5439        select_value_stride    = entry->select_value_stride;
5440        op_count               = entry->op_count;
5441        poll                   = entry->poll;
5442        mask                   = entry->mask;
5443
5444        for (loop_cnt = 0; loop_cnt < op_count; loop_cnt++) {
5445                ret = ql_rdwr_indreg32(ha, select_addr, &select_value, 0);
5446		if (ret)
5447			return (0);
5448
5449                wait_count = 0;
5450
5451                while (wait_count < poll) {
5452                        uint32_t temp;
5453
5454			ret = ql_rdwr_indreg32(ha, select_addr, &temp, 1);
5455			if (ret)
5456				return (0);
5457
5458                        if ( (temp & mask) != 0 ) {
5459                                break;
5460                        }
5461                        wait_count++;
5462                }
5463
5464                if (wait_count == poll) {
5465                        device_printf(ha->pci_dev,
5466				"%s: Error in processing entry\n", __func__);
5467                        device_printf(ha->pci_dev,
5468				"%s: wait_count <0x%x> poll <0x%x>\n",
5469				__func__, wait_count, poll);
5470                        return 0;
5471                }
5472
5473		ret = ql_rdwr_indreg32(ha, read_addr, &data, 1);
5474		if (ret)
5475			return (0);
5476
5477                *data_buff++ = select_value;
5478                *data_buff++ = data;
5479                select_value = select_value + select_value_stride;
5480        }
5481
5482        /*
5483         * for testing purpose we return amount of data written
5484         */
5485        return (loop_cnt * (2 * sizeof(uint32_t)));
5486}
5487
5488/*
5489 * Handling rd modify write poll entry.
5490 */
5491
5492static uint32_t
5493ql_pollrd_modify_write(qla_host_t *ha,
5494	ql_minidump_entry_rd_modify_wr_with_poll_t *entry,
5495	uint32_t *data_buff)
5496{
5497	int ret;
5498        uint32_t addr_1, addr_2, value_1, value_2, data;
5499        uint32_t poll, mask, modify_mask;
5500        uint32_t wait_count = 0;
5501
5502        addr_1		= entry->addr_1;
5503        addr_2		= entry->addr_2;
5504        value_1		= entry->value_1;
5505        value_2		= entry->value_2;
5506
5507        poll		= entry->poll;
5508        mask		= entry->mask;
5509        modify_mask	= entry->modify_mask;
5510
5511	ret = ql_rdwr_indreg32(ha, addr_1, &value_1, 0);
5512	if (ret)
5513		return (0);
5514
5515        wait_count = 0;
5516        while (wait_count < poll) {
5517		uint32_t temp;
5518
5519		ret = ql_rdwr_indreg32(ha, addr_1, &temp, 1);
5520		if (ret)
5521			return (0);
5522
5523                if ( (temp & mask) != 0 ) {
5524                        break;
5525                }
5526                wait_count++;
5527        }
5528
5529        if (wait_count == poll) {
5530                device_printf(ha->pci_dev, "%s Error in processing entry\n",
5531			__func__);
5532        } else {
5533		ret = ql_rdwr_indreg32(ha, addr_2, &data, 1);
5534		if (ret)
5535			return (0);
5536
5537                data = (data & modify_mask);
5538
5539		ret = ql_rdwr_indreg32(ha, addr_2, &data, 0);
5540		if (ret)
5541			return (0);
5542
5543		ret = ql_rdwr_indreg32(ha, addr_1, &value_2, 0);
5544		if (ret)
5545			return (0);
5546
5547                /* Poll again */
5548                wait_count = 0;
5549                while (wait_count < poll) {
5550                        uint32_t temp;
5551
5552			ret = ql_rdwr_indreg32(ha, addr_1, &temp, 1);
5553			if (ret)
5554				return (0);
5555
5556                        if ( (temp & mask) != 0 ) {
5557                                break;
5558                        }
5559                        wait_count++;
5560                }
5561                *data_buff++ = addr_2;
5562                *data_buff++ = data;
5563        }
5564
5565        /*
5566         * for testing purpose we return amount of data written
5567         */
5568        return (2 * sizeof(uint32_t));
5569}
5570