1252206Sdavidcs/*
2252206Sdavidcs * Copyright (c) 2013-2014 Qlogic Corporation
3252206Sdavidcs * All rights reserved.
4252206Sdavidcs *
5252206Sdavidcs *  Redistribution and use in source and binary forms, with or without
6252206Sdavidcs *  modification, are permitted provided that the following conditions
7252206Sdavidcs *  are met:
8252206Sdavidcs *
9252206Sdavidcs *  1. Redistributions of source code must retain the above copyright
10252206Sdavidcs *     notice, this list of conditions and the following disclaimer.
11252206Sdavidcs *  2. Redistributions in binary form must reproduce the above copyright
12252206Sdavidcs *     notice, this list of conditions and the following disclaimer in the
13252206Sdavidcs *     documentation and/or other materials provided with the distribution.
14252206Sdavidcs *
15252206Sdavidcs *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16252206Sdavidcs *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17252206Sdavidcs *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18252206Sdavidcs *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19252206Sdavidcs *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20252206Sdavidcs *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21252206Sdavidcs *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22252206Sdavidcs *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23252206Sdavidcs *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24252206Sdavidcs *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25252206Sdavidcs *  POSSIBILITY OF SUCH DAMAGE.
26252206Sdavidcs */
27252206Sdavidcs
28252206Sdavidcs/*
29252206Sdavidcs * File: qls_hw.c
30252206Sdavidcs * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656.
31252206Sdavidcs * Content: Contains Hardware dependant functions
32252206Sdavidcs */
33252206Sdavidcs#include <sys/cdefs.h>
34252206Sdavidcs__FBSDID("$FreeBSD$");
35252206Sdavidcs
36252206Sdavidcs
37252206Sdavidcs
38252206Sdavidcs#include "qls_os.h"
39252206Sdavidcs#include "qls_hw.h"
40252206Sdavidcs#include "qls_def.h"
41252206Sdavidcs#include "qls_inline.h"
42252206Sdavidcs#include "qls_ver.h"
43252206Sdavidcs#include "qls_glbl.h"
44252206Sdavidcs#include "qls_dbg.h"
45252206Sdavidcs
46252206Sdavidcs/*
47252206Sdavidcs * Static Functions
48252206Sdavidcs */
49252206Sdavidcsstatic int qls_wait_for_mac_proto_idx_ready(qla_host_t *ha, uint32_t op);
50252206Sdavidcsstatic int qls_config_unicast_mac_addr(qla_host_t *ha, uint32_t add_mac);
51252206Sdavidcsstatic int qls_config_mcast_mac_addr(qla_host_t *ha, uint8_t *mac_addr,
52252206Sdavidcs                uint32_t add_mac, uint32_t index);
53252206Sdavidcs
54252206Sdavidcsstatic int qls_init_rss(qla_host_t *ha);
55252206Sdavidcsstatic int qls_init_comp_queue(qla_host_t *ha, int cid);
56252206Sdavidcsstatic int qls_init_work_queue(qla_host_t *ha, int wid);
57252206Sdavidcsstatic int qls_init_fw_routing_table(qla_host_t *ha);
58252206Sdavidcsstatic int qls_hw_add_all_mcast(qla_host_t *ha);
59252206Sdavidcsstatic int qls_hw_add_mcast(qla_host_t *ha, uint8_t *mta);
60252206Sdavidcsstatic int qls_hw_del_mcast(qla_host_t *ha, uint8_t *mta);
61252206Sdavidcsstatic int qls_wait_for_flash_ready(qla_host_t *ha);
62252206Sdavidcs
63252206Sdavidcsstatic int qls_sem_lock(qla_host_t *ha, uint32_t mask, uint32_t value);
64252206Sdavidcsstatic void qls_sem_unlock(qla_host_t *ha, uint32_t mask);
65252206Sdavidcs
66252206Sdavidcsstatic void qls_free_tx_dma(qla_host_t *ha);
67252206Sdavidcsstatic int qls_alloc_tx_dma(qla_host_t *ha);
68252206Sdavidcsstatic void qls_free_rx_dma(qla_host_t *ha);
69252206Sdavidcsstatic int qls_alloc_rx_dma(qla_host_t *ha);
70252206Sdavidcsstatic void qls_free_mpi_dma(qla_host_t *ha);
71252206Sdavidcsstatic int qls_alloc_mpi_dma(qla_host_t *ha);
72252206Sdavidcsstatic void qls_free_rss_dma(qla_host_t *ha);
73252206Sdavidcsstatic int qls_alloc_rss_dma(qla_host_t *ha);
74252206Sdavidcs
75252206Sdavidcsstatic int qls_flash_validate(qla_host_t *ha, const char *signature);
76252206Sdavidcs
77252206Sdavidcs
78252206Sdavidcsstatic int qls_wait_for_proc_addr_ready(qla_host_t *ha);
79252206Sdavidcsstatic int qls_proc_addr_rd_reg(qla_host_t *ha, uint32_t addr_module,
80252206Sdavidcs		uint32_t reg, uint32_t *data);
81252206Sdavidcsstatic int qls_proc_addr_wr_reg(qla_host_t *ha, uint32_t addr_module,
82252206Sdavidcs		uint32_t reg, uint32_t data);
83252206Sdavidcs
84252206Sdavidcsstatic int qls_hw_reset(qla_host_t *ha);
85252206Sdavidcs
86252206Sdavidcs/*
87252206Sdavidcs * MPI Related Functions
88252206Sdavidcs */
89252206Sdavidcsstatic int qls_mbx_cmd(qla_host_t *ha, uint32_t *in_mbx, uint32_t i_count,
90252206Sdavidcs		uint32_t *out_mbx, uint32_t o_count);
91252206Sdavidcsstatic int qls_mbx_set_mgmt_ctrl(qla_host_t *ha, uint32_t t_ctrl);
92252206Sdavidcsstatic int qls_mbx_get_mgmt_ctrl(qla_host_t *ha, uint32_t *t_status);
93252206Sdavidcsstatic void qls_mbx_get_link_status(qla_host_t *ha);
94252206Sdavidcsstatic void qls_mbx_about_fw(qla_host_t *ha);
95252206Sdavidcs
96252206Sdavidcsint
97252206Sdavidcsqls_get_msix_count(qla_host_t *ha)
98252206Sdavidcs{
99252206Sdavidcs	return (ha->num_rx_rings);
100252206Sdavidcs}
101252206Sdavidcs
102252206Sdavidcsstatic int
103252206Sdavidcsqls_syctl_mpi_dump(SYSCTL_HANDLER_ARGS)
104252206Sdavidcs{
105252206Sdavidcs        int err = 0, ret;
106252206Sdavidcs        qla_host_t *ha;
107252206Sdavidcs
108252206Sdavidcs        err = sysctl_handle_int(oidp, &ret, 0, req);
109252206Sdavidcs
110252206Sdavidcs        if (err || !req->newptr)
111252206Sdavidcs                return (err);
112252206Sdavidcs
113252206Sdavidcs
114252206Sdavidcs        if (ret == 1) {
115252206Sdavidcs                ha = (qla_host_t *)arg1;
116252206Sdavidcs		qls_mpi_core_dump(ha);
117252206Sdavidcs        }
118252206Sdavidcs        return (err);
119252206Sdavidcs}
120252206Sdavidcs
121252206Sdavidcsstatic int
122252206Sdavidcsqls_syctl_link_status(SYSCTL_HANDLER_ARGS)
123252206Sdavidcs{
124252206Sdavidcs        int err = 0, ret;
125252206Sdavidcs        qla_host_t *ha;
126252206Sdavidcs
127252206Sdavidcs        err = sysctl_handle_int(oidp, &ret, 0, req);
128252206Sdavidcs
129252206Sdavidcs        if (err || !req->newptr)
130252206Sdavidcs                return (err);
131252206Sdavidcs
132252206Sdavidcs
133252206Sdavidcs        if (ret == 1) {
134252206Sdavidcs                ha = (qla_host_t *)arg1;
135252206Sdavidcs		qls_mbx_get_link_status(ha);
136252206Sdavidcs		qls_mbx_about_fw(ha);
137252206Sdavidcs        }
138252206Sdavidcs        return (err);
139252206Sdavidcs}
140252206Sdavidcs
141252206Sdavidcsvoid
142252206Sdavidcsqls_hw_add_sysctls(qla_host_t *ha)
143252206Sdavidcs{
144252206Sdavidcs        device_t	dev;
145252206Sdavidcs
146252206Sdavidcs        dev = ha->pci_dev;
147252206Sdavidcs
148252206Sdavidcs	ha->num_rx_rings = MAX_RX_RINGS; ha->num_tx_rings = MAX_TX_RINGS;
149252206Sdavidcs
150252206Sdavidcs	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
151252206Sdavidcs		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
152252206Sdavidcs		OID_AUTO, "num_rx_rings", CTLFLAG_RD, &ha->num_rx_rings,
153252206Sdavidcs		ha->num_rx_rings, "Number of Completion Queues");
154252206Sdavidcs
155252206Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
156252206Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
157252206Sdavidcs                OID_AUTO, "num_tx_rings", CTLFLAG_RD, &ha->num_tx_rings,
158252206Sdavidcs		ha->num_tx_rings, "Number of Transmit Rings");
159252206Sdavidcs
160252206Sdavidcs        SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
161252206Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
162252206Sdavidcs                OID_AUTO, "mpi_dump", CTLTYPE_INT | CTLFLAG_RW,
163252206Sdavidcs                (void *)ha, 0,
164252206Sdavidcs                qls_syctl_mpi_dump, "I", "MPI Dump");
165252206Sdavidcs
166252206Sdavidcs        SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
167252206Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
168252206Sdavidcs                OID_AUTO, "link_status", CTLTYPE_INT | CTLFLAG_RW,
169252206Sdavidcs                (void *)ha, 0,
170252206Sdavidcs                qls_syctl_link_status, "I", "Link Status");
171252206Sdavidcs}
172252206Sdavidcs
173252206Sdavidcs/*
174252206Sdavidcs * Name: qls_free_dma
175252206Sdavidcs * Function: Frees the DMA'able memory allocated in qls_alloc_dma()
176252206Sdavidcs */
177252206Sdavidcsvoid
178252206Sdavidcsqls_free_dma(qla_host_t *ha)
179252206Sdavidcs{
180252206Sdavidcs	qls_free_rss_dma(ha);
181252206Sdavidcs	qls_free_mpi_dma(ha);
182252206Sdavidcs	qls_free_tx_dma(ha);
183252206Sdavidcs	qls_free_rx_dma(ha);
184252206Sdavidcs	return;
185252206Sdavidcs}
186252206Sdavidcs
187252206Sdavidcs/*
188252206Sdavidcs * Name: qls_alloc_dma
189252206Sdavidcs * Function: Allocates DMA'able memory for Tx/Rx Rings, Tx/Rx Contexts.
190252206Sdavidcs */
191252206Sdavidcsint
192252206Sdavidcsqls_alloc_dma(qla_host_t *ha)
193252206Sdavidcs{
194252206Sdavidcs	if (qls_alloc_rx_dma(ha))
195252206Sdavidcs		return (-1);
196252206Sdavidcs
197252206Sdavidcs	if (qls_alloc_tx_dma(ha)) {
198252206Sdavidcs		qls_free_rx_dma(ha);
199252206Sdavidcs		return (-1);
200252206Sdavidcs	}
201252206Sdavidcs
202252206Sdavidcs	if (qls_alloc_mpi_dma(ha)) {
203252206Sdavidcs		qls_free_tx_dma(ha);
204252206Sdavidcs		qls_free_rx_dma(ha);
205252206Sdavidcs		return (-1);
206252206Sdavidcs	}
207252206Sdavidcs
208252206Sdavidcs	if (qls_alloc_rss_dma(ha)) {
209252206Sdavidcs		qls_free_mpi_dma(ha);
210252206Sdavidcs		qls_free_tx_dma(ha);
211252206Sdavidcs		qls_free_rx_dma(ha);
212252206Sdavidcs		return (-1);
213252206Sdavidcs	}
214252206Sdavidcs
215252206Sdavidcs	return (0);
216252206Sdavidcs}
217252206Sdavidcs
218252206Sdavidcs
219252206Sdavidcsstatic int
220252206Sdavidcsqls_wait_for_mac_proto_idx_ready(qla_host_t *ha, uint32_t op)
221252206Sdavidcs{
222252206Sdavidcs	uint32_t data32;
223252206Sdavidcs	uint32_t count = 3;
224252206Sdavidcs
225252206Sdavidcs	while (count--) {
226252206Sdavidcs		data32 = READ_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_INDEX);
227252206Sdavidcs
228252206Sdavidcs		if (data32 & op)
229252206Sdavidcs			return (0);
230252206Sdavidcs
231252206Sdavidcs		QLA_USEC_DELAY(100);
232252206Sdavidcs	}
233252206Sdavidcs	ha->qla_initiate_recovery = 1;
234252206Sdavidcs	return (-1);
235252206Sdavidcs}
236252206Sdavidcs
237252206Sdavidcs/*
238252206Sdavidcs * Name: qls_config_unicast_mac_addr
239252206Sdavidcs * Function: binds/unbinds a unicast MAC address to the interface.
240252206Sdavidcs */
241252206Sdavidcsstatic int
242252206Sdavidcsqls_config_unicast_mac_addr(qla_host_t *ha, uint32_t add_mac)
243252206Sdavidcs{
244252206Sdavidcs	int ret = 0;
245252206Sdavidcs	uint32_t mac_upper = 0;
246252206Sdavidcs	uint32_t mac_lower = 0;
247252206Sdavidcs	uint32_t value = 0, index;
248252206Sdavidcs
249252206Sdavidcs	if (qls_sem_lock(ha, Q81_CTL_SEM_MASK_MAC_SERDES,
250252206Sdavidcs		Q81_CTL_SEM_SET_MAC_SERDES)) {
251252206Sdavidcs		QL_DPRINT1((ha->pci_dev, "%s: semlock failed\n", __func__));
252252206Sdavidcs		return(-1);
253252206Sdavidcs	}
254252206Sdavidcs
255252206Sdavidcs	if (add_mac) {
256252206Sdavidcs		mac_upper = (ha->mac_addr[0] << 8) | ha->mac_addr[1];
257252206Sdavidcs		mac_lower = (ha->mac_addr[2] << 24) | (ha->mac_addr[3] << 16) |
258252206Sdavidcs				(ha->mac_addr[4] << 8) | ha->mac_addr[5];
259252206Sdavidcs	}
260252206Sdavidcs	ret = qls_wait_for_mac_proto_idx_ready(ha, Q81_CTL_MAC_PROTO_AI_MW);
261252206Sdavidcs	if (ret)
262252206Sdavidcs		goto qls_config_unicast_mac_addr_exit;
263252206Sdavidcs
264252206Sdavidcs	index = 128 * (ha->pci_func & 0x1); /* index */
265252206Sdavidcs
266252206Sdavidcs	value = (index << Q81_CTL_MAC_PROTO_AI_IDX_SHIFT) |
267252206Sdavidcs		Q81_CTL_MAC_PROTO_AI_TYPE_CAM_MAC;
268252206Sdavidcs
269252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_INDEX, value);
270252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_DATA, mac_lower);
271252206Sdavidcs
272252206Sdavidcs	ret = qls_wait_for_mac_proto_idx_ready(ha, Q81_CTL_MAC_PROTO_AI_MW);
273252206Sdavidcs	if (ret)
274252206Sdavidcs		goto qls_config_unicast_mac_addr_exit;
275252206Sdavidcs
276252206Sdavidcs	value = (index << Q81_CTL_MAC_PROTO_AI_IDX_SHIFT) |
277252206Sdavidcs		Q81_CTL_MAC_PROTO_AI_TYPE_CAM_MAC | 0x1;
278252206Sdavidcs
279252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_INDEX, value);
280252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_DATA, mac_upper);
281252206Sdavidcs
282252206Sdavidcs	ret = qls_wait_for_mac_proto_idx_ready(ha, Q81_CTL_MAC_PROTO_AI_MW);
283252206Sdavidcs	if (ret)
284252206Sdavidcs		goto qls_config_unicast_mac_addr_exit;
285252206Sdavidcs
286252206Sdavidcs	value = (index << Q81_CTL_MAC_PROTO_AI_IDX_SHIFT) |
287252206Sdavidcs		Q81_CTL_MAC_PROTO_AI_TYPE_CAM_MAC | 0x2;
288252206Sdavidcs
289252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_INDEX, value);
290252206Sdavidcs
291252206Sdavidcs	value = Q81_CAM_MAC_OFF2_ROUTE_NIC |
292252206Sdavidcs			((ha->pci_func & 0x1) << Q81_CAM_MAC_OFF2_FUNC_SHIFT) |
293252206Sdavidcs			(0 << Q81_CAM_MAC_OFF2_CQID_SHIFT);
294252206Sdavidcs
295252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_DATA, value);
296252206Sdavidcs
297252206Sdavidcsqls_config_unicast_mac_addr_exit:
298252206Sdavidcs	qls_sem_unlock(ha, Q81_CTL_SEM_MASK_MAC_SERDES);
299252206Sdavidcs	return (ret);
300252206Sdavidcs}
301252206Sdavidcs
302252206Sdavidcs/*
303252206Sdavidcs * Name: qls_config_mcast_mac_addr
304252206Sdavidcs * Function: binds/unbinds a multicast MAC address to the interface.
305252206Sdavidcs */
306252206Sdavidcsstatic int
307252206Sdavidcsqls_config_mcast_mac_addr(qla_host_t *ha, uint8_t *mac_addr, uint32_t add_mac,
308252206Sdavidcs	uint32_t index)
309252206Sdavidcs{
310252206Sdavidcs	int ret = 0;
311252206Sdavidcs	uint32_t mac_upper = 0;
312252206Sdavidcs	uint32_t mac_lower = 0;
313252206Sdavidcs	uint32_t value = 0;
314252206Sdavidcs
315252206Sdavidcs	if (qls_sem_lock(ha, Q81_CTL_SEM_MASK_MAC_SERDES,
316252206Sdavidcs		Q81_CTL_SEM_SET_MAC_SERDES)) {
317252206Sdavidcs		QL_DPRINT1((ha->pci_dev, "%s: semlock failed\n", __func__));
318252206Sdavidcs		return(-1);
319252206Sdavidcs	}
320252206Sdavidcs
321252206Sdavidcs	if (add_mac) {
322252206Sdavidcs		mac_upper = (mac_addr[0] << 8) | mac_addr[1];
323252206Sdavidcs		mac_lower = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
324252206Sdavidcs				(mac_addr[4] << 8) | mac_addr[5];
325252206Sdavidcs	}
326252206Sdavidcs	ret = qls_wait_for_mac_proto_idx_ready(ha, Q81_CTL_MAC_PROTO_AI_MW);
327252206Sdavidcs	if (ret)
328252206Sdavidcs		goto qls_config_mcast_mac_addr_exit;
329252206Sdavidcs
330252206Sdavidcs	value = Q81_CTL_MAC_PROTO_AI_E |
331252206Sdavidcs			(index << Q81_CTL_MAC_PROTO_AI_IDX_SHIFT) |
332252206Sdavidcs			Q81_CTL_MAC_PROTO_AI_TYPE_MCAST ;
333252206Sdavidcs
334252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_INDEX, value);
335252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_DATA, mac_lower);
336252206Sdavidcs
337252206Sdavidcs	ret = qls_wait_for_mac_proto_idx_ready(ha, Q81_CTL_MAC_PROTO_AI_MW);
338252206Sdavidcs	if (ret)
339252206Sdavidcs		goto qls_config_mcast_mac_addr_exit;
340252206Sdavidcs
341252206Sdavidcs	value = Q81_CTL_MAC_PROTO_AI_E |
342252206Sdavidcs			(index << Q81_CTL_MAC_PROTO_AI_IDX_SHIFT) |
343252206Sdavidcs			Q81_CTL_MAC_PROTO_AI_TYPE_MCAST | 0x1;
344252206Sdavidcs
345252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_INDEX, value);
346252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_DATA, mac_upper);
347252206Sdavidcs
348252206Sdavidcsqls_config_mcast_mac_addr_exit:
349252206Sdavidcs	qls_sem_unlock(ha, Q81_CTL_SEM_MASK_MAC_SERDES);
350252206Sdavidcs
351252206Sdavidcs	return (ret);
352252206Sdavidcs}
353252206Sdavidcs
354252206Sdavidcs/*
355252206Sdavidcs * Name: qls_set_mac_rcv_mode
356252206Sdavidcs * Function: Enable/Disable AllMulticast and Promiscous Modes.
357252206Sdavidcs */
358252206Sdavidcsstatic int
359252206Sdavidcsqls_wait_for_route_idx_ready(qla_host_t *ha, uint32_t op)
360252206Sdavidcs{
361252206Sdavidcs	uint32_t data32;
362252206Sdavidcs	uint32_t count = 3;
363252206Sdavidcs
364252206Sdavidcs	while (count--) {
365252206Sdavidcs		data32 = READ_REG32(ha, Q81_CTL_ROUTING_INDEX);
366252206Sdavidcs
367252206Sdavidcs		if (data32 & op)
368252206Sdavidcs			return (0);
369252206Sdavidcs
370252206Sdavidcs		QLA_USEC_DELAY(100);
371252206Sdavidcs	}
372252206Sdavidcs	ha->qla_initiate_recovery = 1;
373252206Sdavidcs	return (-1);
374252206Sdavidcs}
375252206Sdavidcs
376252206Sdavidcsstatic int
377252206Sdavidcsqls_load_route_idx_reg(qla_host_t *ha, uint32_t index, uint32_t data)
378252206Sdavidcs{
379252206Sdavidcs	int ret = 0;
380252206Sdavidcs
381252206Sdavidcs	ret = qls_wait_for_route_idx_ready(ha, Q81_CTL_RI_MW);
382252206Sdavidcs
383252206Sdavidcs	if (ret) {
384252206Sdavidcs		device_printf(ha->pci_dev, "%s: [0x%08x, 0x%08x] failed\n",
385252206Sdavidcs			__func__, index, data);
386252206Sdavidcs		goto qls_load_route_idx_reg_exit;
387252206Sdavidcs	}
388252206Sdavidcs
389252206Sdavidcs
390252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_ROUTING_INDEX, index);
391252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_ROUTING_DATA, data);
392252206Sdavidcs
393252206Sdavidcsqls_load_route_idx_reg_exit:
394252206Sdavidcs	return (ret);
395252206Sdavidcs}
396252206Sdavidcs
397252206Sdavidcsstatic int
398252206Sdavidcsqls_load_route_idx_reg_locked(qla_host_t *ha, uint32_t index, uint32_t data)
399252206Sdavidcs{
400252206Sdavidcs	int ret = 0;
401252206Sdavidcs
402252206Sdavidcs	if (qls_sem_lock(ha, Q81_CTL_SEM_MASK_RIDX_DATAREG,
403252206Sdavidcs		Q81_CTL_SEM_SET_RIDX_DATAREG)) {
404252206Sdavidcs		QL_DPRINT1((ha->pci_dev, "%s: semlock failed\n", __func__));
405252206Sdavidcs		return(-1);
406252206Sdavidcs	}
407252206Sdavidcs
408252206Sdavidcs	ret = qls_load_route_idx_reg(ha, index, data);
409252206Sdavidcs
410252206Sdavidcs	qls_sem_unlock(ha, Q81_CTL_SEM_MASK_RIDX_DATAREG);
411252206Sdavidcs
412252206Sdavidcs	return (ret);
413252206Sdavidcs}
414252206Sdavidcs
415252206Sdavidcsstatic int
416252206Sdavidcsqls_clear_routing_table(qla_host_t *ha)
417252206Sdavidcs{
418252206Sdavidcs	int i, ret = 0;
419252206Sdavidcs
420252206Sdavidcs	if (qls_sem_lock(ha, Q81_CTL_SEM_MASK_RIDX_DATAREG,
421252206Sdavidcs		Q81_CTL_SEM_SET_RIDX_DATAREG)) {
422252206Sdavidcs		QL_DPRINT1((ha->pci_dev, "%s: semlock failed\n", __func__));
423252206Sdavidcs		return(-1);
424252206Sdavidcs	}
425252206Sdavidcs
426252206Sdavidcs	for (i = 0; i < 16; i++) {
427252206Sdavidcs		ret = qls_load_route_idx_reg(ha, (Q81_CTL_RI_TYPE_NICQMASK|
428252206Sdavidcs			(i << 8) | Q81_CTL_RI_DST_DFLTQ), 0);
429252206Sdavidcs		if (ret)
430252206Sdavidcs			break;
431252206Sdavidcs	}
432252206Sdavidcs
433252206Sdavidcs	qls_sem_unlock(ha, Q81_CTL_SEM_MASK_RIDX_DATAREG);
434252206Sdavidcs
435252206Sdavidcs	return (ret);
436252206Sdavidcs}
437252206Sdavidcs
438252206Sdavidcsint
439252206Sdavidcsqls_set_promisc(qla_host_t *ha)
440252206Sdavidcs{
441252206Sdavidcs	int ret;
442252206Sdavidcs
443252206Sdavidcs	ret = qls_load_route_idx_reg_locked(ha,
444252206Sdavidcs			(Q81_CTL_RI_E | Q81_CTL_RI_TYPE_NICQMASK |
445252206Sdavidcs			Q81_CTL_RI_IDX_PROMISCUOUS | Q81_CTL_RI_DST_DFLTQ),
446252206Sdavidcs			Q81_CTL_RD_VALID_PKT);
447252206Sdavidcs	return (ret);
448252206Sdavidcs}
449252206Sdavidcs
450252206Sdavidcsvoid
451252206Sdavidcsqls_reset_promisc(qla_host_t *ha)
452252206Sdavidcs{
453252206Sdavidcs	int ret;
454252206Sdavidcs
455252206Sdavidcs	ret = qls_load_route_idx_reg_locked(ha, (Q81_CTL_RI_TYPE_NICQMASK |
456252206Sdavidcs			Q81_CTL_RI_IDX_PROMISCUOUS | Q81_CTL_RI_DST_DFLTQ), 0);
457252206Sdavidcs	return;
458252206Sdavidcs}
459252206Sdavidcs
460252206Sdavidcsint
461252206Sdavidcsqls_set_allmulti(qla_host_t *ha)
462252206Sdavidcs{
463252206Sdavidcs	int ret;
464252206Sdavidcs
465252206Sdavidcs	ret = qls_load_route_idx_reg_locked(ha,
466252206Sdavidcs			(Q81_CTL_RI_E | Q81_CTL_RI_TYPE_NICQMASK |
467252206Sdavidcs			Q81_CTL_RI_IDX_ALLMULTI | Q81_CTL_RI_DST_DFLTQ),
468252206Sdavidcs			Q81_CTL_RD_MCAST);
469252206Sdavidcs	return (ret);
470252206Sdavidcs}
471252206Sdavidcs
472252206Sdavidcsvoid
473252206Sdavidcsqls_reset_allmulti(qla_host_t *ha)
474252206Sdavidcs{
475252206Sdavidcs	int ret;
476252206Sdavidcs
477252206Sdavidcs	ret = qls_load_route_idx_reg_locked(ha, (Q81_CTL_RI_TYPE_NICQMASK |
478252206Sdavidcs			Q81_CTL_RI_IDX_ALLMULTI | Q81_CTL_RI_DST_DFLTQ), 0);
479252206Sdavidcs	return;
480252206Sdavidcs}
481252206Sdavidcs
482252206Sdavidcs
483252206Sdavidcsstatic int
484252206Sdavidcsqls_init_fw_routing_table(qla_host_t *ha)
485252206Sdavidcs{
486252206Sdavidcs	int ret = 0;
487252206Sdavidcs
488252206Sdavidcs	ret = qls_clear_routing_table(ha);
489252206Sdavidcs	if (ret)
490252206Sdavidcs		return (-1);
491252206Sdavidcs
492252206Sdavidcs	if (qls_sem_lock(ha, Q81_CTL_SEM_MASK_RIDX_DATAREG,
493252206Sdavidcs		Q81_CTL_SEM_SET_RIDX_DATAREG)) {
494252206Sdavidcs		QL_DPRINT1((ha->pci_dev, "%s: semlock failed\n", __func__));
495252206Sdavidcs		return(-1);
496252206Sdavidcs	}
497252206Sdavidcs
498252206Sdavidcs	ret = qls_load_route_idx_reg(ha, (Q81_CTL_RI_E | Q81_CTL_RI_DST_DROP |
499252206Sdavidcs			Q81_CTL_RI_TYPE_NICQMASK | Q81_CTL_RI_IDX_ALL_ERROR),
500252206Sdavidcs			Q81_CTL_RD_ERROR_PKT);
501252206Sdavidcs	if (ret)
502252206Sdavidcs		goto qls_init_fw_routing_table_exit;
503252206Sdavidcs
504252206Sdavidcs	ret = qls_load_route_idx_reg(ha, (Q81_CTL_RI_E | Q81_CTL_RI_DST_DFLTQ |
505252206Sdavidcs			Q81_CTL_RI_TYPE_NICQMASK | Q81_CTL_RI_IDX_BCAST),
506252206Sdavidcs			Q81_CTL_RD_BCAST);
507252206Sdavidcs	if (ret)
508252206Sdavidcs		goto qls_init_fw_routing_table_exit;
509252206Sdavidcs
510252206Sdavidcs	if (ha->num_rx_rings > 1 ) {
511252206Sdavidcs		ret = qls_load_route_idx_reg(ha,
512252206Sdavidcs				(Q81_CTL_RI_E | Q81_CTL_RI_DST_RSS |
513252206Sdavidcs				Q81_CTL_RI_TYPE_NICQMASK |
514252206Sdavidcs				Q81_CTL_RI_IDX_RSS_MATCH),
515252206Sdavidcs				Q81_CTL_RD_RSS_MATCH);
516252206Sdavidcs		if (ret)
517252206Sdavidcs			goto qls_init_fw_routing_table_exit;
518252206Sdavidcs	}
519252206Sdavidcs
520252206Sdavidcs	ret = qls_load_route_idx_reg(ha, (Q81_CTL_RI_E | Q81_CTL_RI_DST_DFLTQ |
521252206Sdavidcs			Q81_CTL_RI_TYPE_NICQMASK | Q81_CTL_RI_IDX_MCAST_MATCH),
522252206Sdavidcs			Q81_CTL_RD_MCAST_REG_MATCH);
523252206Sdavidcs	if (ret)
524252206Sdavidcs		goto qls_init_fw_routing_table_exit;
525252206Sdavidcs
526252206Sdavidcs	ret = qls_load_route_idx_reg(ha, (Q81_CTL_RI_E | Q81_CTL_RI_DST_DFLTQ |
527252206Sdavidcs			Q81_CTL_RI_TYPE_NICQMASK | Q81_CTL_RI_IDX_CAM_HIT),
528252206Sdavidcs			Q81_CTL_RD_CAM_HIT);
529252206Sdavidcs	if (ret)
530252206Sdavidcs		goto qls_init_fw_routing_table_exit;
531252206Sdavidcs
532252206Sdavidcsqls_init_fw_routing_table_exit:
533252206Sdavidcs	qls_sem_unlock(ha, Q81_CTL_SEM_MASK_RIDX_DATAREG);
534252206Sdavidcs	return (ret);
535252206Sdavidcs}
536252206Sdavidcs
537252206Sdavidcsstatic int
538252206Sdavidcsqls_tx_tso_chksum(qla_host_t *ha, struct mbuf *mp, q81_tx_tso_t *tx_mac)
539252206Sdavidcs{
540252206Sdavidcs        struct ether_vlan_header *eh;
541252206Sdavidcs        struct ip *ip;
542252206Sdavidcs        struct ip6_hdr *ip6;
543252206Sdavidcs	struct tcphdr *th;
544252206Sdavidcs        uint32_t ehdrlen, ip_hlen;
545252206Sdavidcs	int ret = 0;
546252206Sdavidcs        uint16_t etype;
547252206Sdavidcs        device_t dev;
548252206Sdavidcs        uint8_t buf[sizeof(struct ip6_hdr)];
549252206Sdavidcs
550252206Sdavidcs        dev = ha->pci_dev;
551252206Sdavidcs
552252206Sdavidcs        eh = mtod(mp, struct ether_vlan_header *);
553252206Sdavidcs
554252206Sdavidcs        if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
555252206Sdavidcs                ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
556252206Sdavidcs                etype = ntohs(eh->evl_proto);
557252206Sdavidcs        } else {
558252206Sdavidcs                ehdrlen = ETHER_HDR_LEN;
559252206Sdavidcs                etype = ntohs(eh->evl_encap_proto);
560252206Sdavidcs        }
561252206Sdavidcs
562252206Sdavidcs        switch (etype) {
563252206Sdavidcs                case ETHERTYPE_IP:
564252206Sdavidcs                        ip = (struct ip *)(mp->m_data + ehdrlen);
565252206Sdavidcs
566252206Sdavidcs                        ip_hlen = sizeof (struct ip);
567252206Sdavidcs
568252206Sdavidcs                        if (mp->m_len < (ehdrlen + ip_hlen)) {
569252206Sdavidcs                                m_copydata(mp, ehdrlen, sizeof(struct ip), buf);
570252206Sdavidcs                                ip = (struct ip *)buf;
571252206Sdavidcs                        }
572252206Sdavidcs			tx_mac->opcode = Q81_IOCB_TX_TSO;
573252206Sdavidcs			tx_mac->flags |= Q81_TX_TSO_FLAGS_IPV4 ;
574252206Sdavidcs
575252206Sdavidcs			tx_mac->phdr_offsets = ehdrlen;
576252206Sdavidcs
577252206Sdavidcs			tx_mac->phdr_offsets |= ((ehdrlen + ip_hlen) <<
578252206Sdavidcs							Q81_TX_TSO_PHDR_SHIFT);
579252206Sdavidcs
580252206Sdavidcs			ip->ip_sum = 0;
581252206Sdavidcs
582252206Sdavidcs			if (mp->m_pkthdr.csum_flags & CSUM_TSO) {
583252206Sdavidcs				tx_mac->flags |= Q81_TX_TSO_FLAGS_LSO;
584252206Sdavidcs
585252206Sdavidcs				th = (struct tcphdr *)(ip + 1);
586252206Sdavidcs
587252206Sdavidcs				th->th_sum = in_pseudo(ip->ip_src.s_addr,
588252206Sdavidcs						ip->ip_dst.s_addr,
589252206Sdavidcs						htons(IPPROTO_TCP));
590252206Sdavidcs				tx_mac->mss = mp->m_pkthdr.tso_segsz;
591252206Sdavidcs				tx_mac->phdr_length = ip_hlen + ehdrlen +
592252206Sdavidcs							(th->th_off << 2);
593252206Sdavidcs				break;
594252206Sdavidcs			}
595252206Sdavidcs			tx_mac->vlan_off |= Q81_TX_TSO_VLAN_OFF_IC ;
596252206Sdavidcs
597252206Sdavidcs
598252206Sdavidcs                        if (ip->ip_p == IPPROTO_TCP) {
599252206Sdavidcs				tx_mac->flags |= Q81_TX_TSO_FLAGS_TC;
600252206Sdavidcs                        } else if (ip->ip_p == IPPROTO_UDP) {
601252206Sdavidcs				tx_mac->flags |= Q81_TX_TSO_FLAGS_UC;
602252206Sdavidcs                        }
603252206Sdavidcs                break;
604252206Sdavidcs
605252206Sdavidcs                case ETHERTYPE_IPV6:
606252206Sdavidcs                        ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen);
607252206Sdavidcs
608252206Sdavidcs                        ip_hlen = sizeof(struct ip6_hdr);
609252206Sdavidcs
610252206Sdavidcs                        if (mp->m_len < (ehdrlen + ip_hlen)) {
611252206Sdavidcs                                m_copydata(mp, ehdrlen, sizeof (struct ip6_hdr),
612252206Sdavidcs                                        buf);
613252206Sdavidcs                                ip6 = (struct ip6_hdr *)buf;
614252206Sdavidcs                        }
615252206Sdavidcs
616252206Sdavidcs			tx_mac->opcode = Q81_IOCB_TX_TSO;
617252206Sdavidcs			tx_mac->flags |= Q81_TX_TSO_FLAGS_IPV6 ;
618252206Sdavidcs			tx_mac->vlan_off |= Q81_TX_TSO_VLAN_OFF_IC ;
619252206Sdavidcs
620252206Sdavidcs			tx_mac->phdr_offsets = ehdrlen;
621252206Sdavidcs			tx_mac->phdr_offsets |= ((ehdrlen + ip_hlen) <<
622252206Sdavidcs							Q81_TX_TSO_PHDR_SHIFT);
623252206Sdavidcs
624252206Sdavidcs                        if (ip6->ip6_nxt == IPPROTO_TCP) {
625252206Sdavidcs				tx_mac->flags |= Q81_TX_TSO_FLAGS_TC;
626252206Sdavidcs                        } else if (ip6->ip6_nxt == IPPROTO_UDP) {
627252206Sdavidcs				tx_mac->flags |= Q81_TX_TSO_FLAGS_UC;
628252206Sdavidcs                        }
629252206Sdavidcs                break;
630252206Sdavidcs
631252206Sdavidcs                default:
632252206Sdavidcs                        ret = -1;
633252206Sdavidcs                break;
634252206Sdavidcs        }
635252206Sdavidcs
636252206Sdavidcs        return (ret);
637252206Sdavidcs}
638252206Sdavidcs
639252206Sdavidcs#define QLA_TX_MIN_FREE 2
640252206Sdavidcsint
641252206Sdavidcsqls_hw_tx_done(qla_host_t *ha, uint32_t txr_idx)
642252206Sdavidcs{
643252206Sdavidcs	uint32_t txr_done, txr_next;
644252206Sdavidcs
645252206Sdavidcs	txr_done = ha->tx_ring[txr_idx].txr_done;
646252206Sdavidcs	txr_next = ha->tx_ring[txr_idx].txr_next;
647252206Sdavidcs
648252206Sdavidcs	if (txr_done == txr_next) {
649252206Sdavidcs		ha->tx_ring[txr_idx].txr_free = NUM_TX_DESCRIPTORS;
650252206Sdavidcs	} else if (txr_done > txr_next) {
651252206Sdavidcs		ha->tx_ring[txr_idx].txr_free = txr_done - txr_next;
652252206Sdavidcs	} else {
653252206Sdavidcs		ha->tx_ring[txr_idx].txr_free = NUM_TX_DESCRIPTORS +
654252206Sdavidcs			txr_done - txr_next;
655252206Sdavidcs	}
656252206Sdavidcs
657252206Sdavidcs	if (ha->tx_ring[txr_idx].txr_free <= QLA_TX_MIN_FREE)
658252206Sdavidcs		return (-1);
659252206Sdavidcs
660252206Sdavidcs	return (0);
661252206Sdavidcs}
662252206Sdavidcs
663252206Sdavidcs/*
664252206Sdavidcs * Name: qls_hw_send
665252206Sdavidcs * Function: Transmits a packet. It first checks if the packet is a
666252206Sdavidcs *	candidate for Large TCP Segment Offload and then for UDP/TCP checksum
667252206Sdavidcs *	offload. If either of these creteria are not met, it is transmitted
668252206Sdavidcs *	as a regular ethernet frame.
669252206Sdavidcs */
670252206Sdavidcsint
671252206Sdavidcsqls_hw_send(qla_host_t *ha, bus_dma_segment_t *segs, int nsegs,
672252206Sdavidcs	uint32_t txr_next,  struct mbuf *mp, uint32_t txr_idx)
673252206Sdavidcs{
674252206Sdavidcs        q81_tx_mac_t *tx_mac;
675252206Sdavidcs	q81_txb_desc_t *tx_desc;
676252206Sdavidcs        uint32_t total_length = 0;
677252206Sdavidcs        uint32_t i;
678252206Sdavidcs        device_t dev;
679252206Sdavidcs	int ret = 0;
680252206Sdavidcs
681252206Sdavidcs	dev = ha->pci_dev;
682252206Sdavidcs
683252206Sdavidcs        total_length = mp->m_pkthdr.len;
684252206Sdavidcs
685252206Sdavidcs        if (total_length > QLA_MAX_TSO_FRAME_SIZE) {
686252206Sdavidcs                device_printf(dev, "%s: total length exceeds maxlen(%d)\n",
687252206Sdavidcs                        __func__, total_length);
688252206Sdavidcs                return (-1);
689252206Sdavidcs        }
690252206Sdavidcs
691252206Sdavidcs	if (ha->tx_ring[txr_idx].txr_free <= (NUM_TX_DESCRIPTORS >> 2)) {
692252206Sdavidcs		if (qls_hw_tx_done(ha, txr_idx)) {
693252206Sdavidcs			device_printf(dev, "%s: tx_free[%d] = %d\n",
694252206Sdavidcs				__func__, txr_idx,
695252206Sdavidcs				ha->tx_ring[txr_idx].txr_free);
696252206Sdavidcs			return (-1);
697252206Sdavidcs		}
698252206Sdavidcs	}
699252206Sdavidcs
700252206Sdavidcs	tx_mac = (q81_tx_mac_t *)&ha->tx_ring[txr_idx].wq_vaddr[txr_next];
701252206Sdavidcs
702252206Sdavidcs	bzero(tx_mac, sizeof(q81_tx_mac_t));
703252206Sdavidcs
704252206Sdavidcs	if ((mp->m_pkthdr.csum_flags &
705252206Sdavidcs			(CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO)) != 0) {
706252206Sdavidcs
707252206Sdavidcs		ret = qls_tx_tso_chksum(ha, mp, (q81_tx_tso_t *)tx_mac);
708252206Sdavidcs		if (ret)
709252206Sdavidcs			return (EINVAL);
710252206Sdavidcs
711252206Sdavidcs		if (mp->m_pkthdr.csum_flags & CSUM_TSO)
712252206Sdavidcs			ha->tx_ring[txr_idx].tx_tso_frames++;
713252206Sdavidcs		else
714252206Sdavidcs			ha->tx_ring[txr_idx].tx_frames++;
715252206Sdavidcs
716252206Sdavidcs	} else {
717252206Sdavidcs		tx_mac->opcode = Q81_IOCB_TX_MAC;
718252206Sdavidcs	}
719252206Sdavidcs
720252206Sdavidcs	if (mp->m_flags & M_VLANTAG) {
721252206Sdavidcs
722252206Sdavidcs		tx_mac->vlan_tci = mp->m_pkthdr.ether_vtag;
723252206Sdavidcs		tx_mac->vlan_off |= Q81_TX_MAC_VLAN_OFF_V;
724252206Sdavidcs
725252206Sdavidcs		ha->tx_ring[txr_idx].tx_vlan_frames++;
726252206Sdavidcs	}
727252206Sdavidcs
728252206Sdavidcs	tx_mac->frame_length = total_length;
729252206Sdavidcs
730252206Sdavidcs	tx_mac->tid_lo = txr_next;
731252206Sdavidcs
732252206Sdavidcs	if (nsegs <= MAX_TX_MAC_DESC) {
733252206Sdavidcs
734252206Sdavidcs		QL_DPRINT2((dev, "%s: 1 [%d, %d]\n", __func__, total_length,
735252206Sdavidcs			tx_mac->tid_lo));
736252206Sdavidcs
737252206Sdavidcs		for (i = 0; i < nsegs; i++) {
738252206Sdavidcs			tx_mac->txd[i].baddr = segs->ds_addr;
739252206Sdavidcs			tx_mac->txd[i].length = segs->ds_len;
740252206Sdavidcs			segs++;
741252206Sdavidcs		}
742252206Sdavidcs		tx_mac->txd[(nsegs - 1)].flags = Q81_RXB_DESC_FLAGS_E;
743252206Sdavidcs
744252206Sdavidcs	} else {
745252206Sdavidcs		QL_DPRINT2((dev, "%s: 2 [%d, %d]\n", __func__, total_length,
746252206Sdavidcs			tx_mac->tid_lo));
747252206Sdavidcs
748252206Sdavidcs		tx_mac->txd[0].baddr =
749252206Sdavidcs			ha->tx_ring[txr_idx].tx_buf[txr_next].oal_paddr;
750252206Sdavidcs		tx_mac->txd[0].length =
751252206Sdavidcs			nsegs * (sizeof(q81_txb_desc_t));
752252206Sdavidcs		tx_mac->txd[0].flags = Q81_RXB_DESC_FLAGS_C;
753252206Sdavidcs
754252206Sdavidcs		tx_desc = ha->tx_ring[txr_idx].tx_buf[txr_next].oal_vaddr;
755252206Sdavidcs
756252206Sdavidcs		for (i = 0; i < nsegs; i++) {
757252206Sdavidcs			tx_desc->baddr = segs->ds_addr;
758252206Sdavidcs			tx_desc->length = segs->ds_len;
759252206Sdavidcs
760252206Sdavidcs			if (i == (nsegs -1))
761252206Sdavidcs				tx_desc->flags = Q81_RXB_DESC_FLAGS_E;
762252206Sdavidcs			else
763252206Sdavidcs				tx_desc->flags = 0;
764252206Sdavidcs
765252206Sdavidcs			segs++;
766252206Sdavidcs			tx_desc++;
767252206Sdavidcs		}
768252206Sdavidcs	}
769252206Sdavidcs	txr_next = (txr_next + 1) & (NUM_TX_DESCRIPTORS - 1);
770252206Sdavidcs	ha->tx_ring[txr_idx].txr_next = txr_next;
771252206Sdavidcs
772252206Sdavidcs	ha->tx_ring[txr_idx].txr_free--;
773252206Sdavidcs
774252206Sdavidcs	Q81_WR_WQ_PROD_IDX(txr_idx, txr_next);
775252206Sdavidcs
776252206Sdavidcs	return (0);
777252206Sdavidcs}
778252206Sdavidcs
779252206Sdavidcs/*
780252206Sdavidcs * Name: qls_del_hw_if
781252206Sdavidcs * Function: Destroys the hardware specific entities corresponding to an
782252206Sdavidcs *	Ethernet Interface
783252206Sdavidcs */
784252206Sdavidcsvoid
785252206Sdavidcsqls_del_hw_if(qla_host_t *ha)
786252206Sdavidcs{
787252206Sdavidcs	uint32_t value;
788252206Sdavidcs	int i;
789252206Sdavidcs	//int  count;
790252206Sdavidcs
791252206Sdavidcs	if (ha->hw_init == 0) {
792252206Sdavidcs		qls_hw_reset(ha);
793252206Sdavidcs		return;
794252206Sdavidcs	}
795252206Sdavidcs
796252206Sdavidcs	for (i = 0;  i < ha->num_tx_rings; i++) {
797252206Sdavidcs		Q81_SET_WQ_INVALID(i);
798252206Sdavidcs	}
799252206Sdavidcs	for (i = 0;  i < ha->num_rx_rings; i++) {
800252206Sdavidcs		Q81_SET_CQ_INVALID(i);
801252206Sdavidcs	}
802252206Sdavidcs
803252206Sdavidcs	for (i = 0; i < ha->num_rx_rings; i++) {
804252206Sdavidcs		Q81_DISABLE_INTR(ha, i); /* MSI-x i */
805252206Sdavidcs	}
806252206Sdavidcs
807252206Sdavidcs	value = (Q81_CTL_INTRE_IHD << Q81_CTL_INTRE_MASK_SHIFT);
808252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_INTR_ENABLE, value);
809252206Sdavidcs
810252206Sdavidcs	value = (Q81_CTL_INTRE_EI << Q81_CTL_INTRE_MASK_SHIFT);
811252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_INTR_ENABLE, value);
812252206Sdavidcs	ha->flags.intr_enable = 0;
813252206Sdavidcs
814252206Sdavidcs	qls_hw_reset(ha);
815252206Sdavidcs
816252206Sdavidcs	return;
817252206Sdavidcs}
818252206Sdavidcs
819252206Sdavidcs/*
820252206Sdavidcs * Name: qls_init_hw_if
821252206Sdavidcs * Function: Creates the hardware specific entities corresponding to an
822252206Sdavidcs *	Ethernet Interface - Transmit and Receive Contexts. Sets the MAC Address
823252206Sdavidcs *	corresponding to the interface. Enables LRO if allowed.
824252206Sdavidcs */
825252206Sdavidcsint
826252206Sdavidcsqls_init_hw_if(qla_host_t *ha)
827252206Sdavidcs{
828252206Sdavidcs	device_t	dev;
829252206Sdavidcs	uint32_t	value;
830252206Sdavidcs	int		ret = 0;
831252206Sdavidcs	int		i;
832252206Sdavidcs
833252206Sdavidcs
834252206Sdavidcs	QL_DPRINT2((ha->pci_dev, "%s:enter\n", __func__));
835252206Sdavidcs
836252206Sdavidcs	dev = ha->pci_dev;
837252206Sdavidcs
838252206Sdavidcs	ret = qls_hw_reset(ha);
839252206Sdavidcs	if (ret)
840252206Sdavidcs		goto qls_init_hw_if_exit;
841252206Sdavidcs
842252206Sdavidcs	ha->vm_pgsize = 4096;
843252206Sdavidcs
844252206Sdavidcs	/* Enable FAE and EFE bits in System Register */
845252206Sdavidcs	value = Q81_CTL_SYSTEM_ENABLE_FAE | Q81_CTL_SYSTEM_ENABLE_EFE;
846252206Sdavidcs	value = (value << Q81_CTL_SYSTEM_MASK_SHIFT) | value;
847252206Sdavidcs
848252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_SYSTEM, value);
849252206Sdavidcs
850252206Sdavidcs	/* Set Default Completion Queue_ID in NIC Rcv Configuration Register */
851252206Sdavidcs	value = (Q81_CTL_NIC_RCVC_DCQ_MASK << Q81_CTL_NIC_RCVC_MASK_SHIFT);
852252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_NIC_RCV_CONFIG, value);
853252206Sdavidcs
854252206Sdavidcs	/* Function Specific Control Register - Set Page Size and Enable NIC */
855252206Sdavidcs	value = Q81_CTL_FUNC_SPECIFIC_FE |
856252206Sdavidcs		Q81_CTL_FUNC_SPECIFIC_VM_PGSIZE_MASK |
857252206Sdavidcs		Q81_CTL_FUNC_SPECIFIC_EPC_O |
858252206Sdavidcs		Q81_CTL_FUNC_SPECIFIC_EPC_I |
859252206Sdavidcs		Q81_CTL_FUNC_SPECIFIC_EC;
860252206Sdavidcs	value = (value << Q81_CTL_FUNC_SPECIFIC_MASK_SHIFT) |
861252206Sdavidcs                        Q81_CTL_FUNC_SPECIFIC_FE |
862252206Sdavidcs			Q81_CTL_FUNC_SPECIFIC_VM_PGSIZE_4K |
863252206Sdavidcs			Q81_CTL_FUNC_SPECIFIC_EPC_O |
864252206Sdavidcs			Q81_CTL_FUNC_SPECIFIC_EPC_I |
865252206Sdavidcs			Q81_CTL_FUNC_SPECIFIC_EC;
866252206Sdavidcs
867252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_FUNC_SPECIFIC, value);
868252206Sdavidcs
869252206Sdavidcs	/* Interrupt Mask Register */
870252206Sdavidcs	value = Q81_CTL_INTRM_PI;
871252206Sdavidcs	value = (value << Q81_CTL_INTRM_MASK_SHIFT) | value;
872252206Sdavidcs
873252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_INTR_MASK, value);
874252206Sdavidcs
875252206Sdavidcs	/* Initialiatize Completion Queue */
876252206Sdavidcs	for (i = 0; i < ha->num_rx_rings; i++) {
877252206Sdavidcs		ret = qls_init_comp_queue(ha, i);
878252206Sdavidcs		if (ret)
879252206Sdavidcs			goto qls_init_hw_if_exit;
880252206Sdavidcs	}
881252206Sdavidcs
882252206Sdavidcs	if (ha->num_rx_rings > 1 ) {
883252206Sdavidcs		ret = qls_init_rss(ha);
884252206Sdavidcs		if (ret)
885252206Sdavidcs			goto qls_init_hw_if_exit;
886252206Sdavidcs	}
887252206Sdavidcs
888252206Sdavidcs	/* Initialize Work Queue */
889252206Sdavidcs
890252206Sdavidcs	for (i = 0; i < ha->num_tx_rings; i++) {
891252206Sdavidcs		ret = qls_init_work_queue(ha, i);
892252206Sdavidcs		if (ret)
893252206Sdavidcs			goto qls_init_hw_if_exit;
894252206Sdavidcs	}
895252206Sdavidcs
896252206Sdavidcs	if (ret)
897252206Sdavidcs		goto qls_init_hw_if_exit;
898252206Sdavidcs
899252206Sdavidcs	/* Set up CAM RAM with MAC Address */
900252206Sdavidcs	ret = qls_config_unicast_mac_addr(ha, 1);
901252206Sdavidcs	if (ret)
902252206Sdavidcs		goto qls_init_hw_if_exit;
903252206Sdavidcs
904252206Sdavidcs	ret = qls_hw_add_all_mcast(ha);
905252206Sdavidcs	if (ret)
906252206Sdavidcs		goto qls_init_hw_if_exit;
907252206Sdavidcs
908252206Sdavidcs	/* Initialize Firmware Routing Table */
909252206Sdavidcs	ret = qls_init_fw_routing_table(ha);
910252206Sdavidcs	if (ret)
911252206Sdavidcs		goto qls_init_hw_if_exit;
912252206Sdavidcs
913252206Sdavidcs	/* Get Chip Revision ID */
914252206Sdavidcs	ha->rev_id = READ_REG32(ha, Q81_CTL_REV_ID);
915252206Sdavidcs
916252206Sdavidcs	/* Enable Global Interrupt */
917252206Sdavidcs	value = Q81_CTL_INTRE_EI;
918252206Sdavidcs	value = (value << Q81_CTL_INTRE_MASK_SHIFT) | value;
919252206Sdavidcs
920252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_INTR_ENABLE, value);
921252206Sdavidcs
922252206Sdavidcs	/* Enable Interrupt Handshake Disable */
923252206Sdavidcs	value = Q81_CTL_INTRE_IHD;
924252206Sdavidcs	value = (value << Q81_CTL_INTRE_MASK_SHIFT) | value;
925252206Sdavidcs
926252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_INTR_ENABLE, value);
927252206Sdavidcs
928252206Sdavidcs	/* Enable Completion Interrupt */
929252206Sdavidcs
930252206Sdavidcs	ha->flags.intr_enable = 1;
931252206Sdavidcs
932252206Sdavidcs	for (i = 0; i < ha->num_rx_rings; i++) {
933252206Sdavidcs		Q81_ENABLE_INTR(ha, i); /* MSI-x i */
934252206Sdavidcs	}
935252206Sdavidcs
936252206Sdavidcs	ha->hw_init = 1;
937252206Sdavidcs
938252206Sdavidcs	qls_mbx_get_link_status(ha);
939252206Sdavidcs
940252206Sdavidcs	QL_DPRINT2((ha->pci_dev, "%s:rxr [0x%08x]\n", __func__,
941252206Sdavidcs		ha->rx_ring[0].cq_db_offset));
942252206Sdavidcs	QL_DPRINT2((ha->pci_dev, "%s:txr [0x%08x]\n", __func__,
943252206Sdavidcs		ha->tx_ring[0].wq_db_offset));
944252206Sdavidcs
945252206Sdavidcs	for (i = 0; i < ha->num_rx_rings; i++) {
946252206Sdavidcs
947252206Sdavidcs		Q81_WR_CQ_CONS_IDX(i, 0);
948252206Sdavidcs		Q81_WR_LBQ_PROD_IDX(i, ha->rx_ring[i].lbq_in);
949252206Sdavidcs		Q81_WR_SBQ_PROD_IDX(i, ha->rx_ring[i].sbq_in);
950252206Sdavidcs
951252206Sdavidcs		QL_DPRINT2((dev, "%s: [wq_idx, cq_idx, lbq_idx, sbq_idx]"
952252206Sdavidcs			"[0x%08x, 0x%08x, 0x%08x, 0x%08x]\n", __func__,
953252206Sdavidcs			Q81_RD_WQ_IDX(i), Q81_RD_CQ_IDX(i), Q81_RD_LBQ_IDX(i),
954252206Sdavidcs			Q81_RD_SBQ_IDX(i)));
955252206Sdavidcs	}
956252206Sdavidcs
957252206Sdavidcs	for (i = 0; i < ha->num_rx_rings; i++) {
958252206Sdavidcs		Q81_SET_CQ_VALID(i);
959252206Sdavidcs	}
960252206Sdavidcs
961252206Sdavidcsqls_init_hw_if_exit:
962252206Sdavidcs	QL_DPRINT2((ha->pci_dev, "%s:exit\n", __func__));
963252206Sdavidcs	return (ret);
964252206Sdavidcs}
965252206Sdavidcs
966252206Sdavidcsstatic int
967252206Sdavidcsqls_wait_for_config_reg_bits(qla_host_t *ha, uint32_t bits, uint32_t value)
968252206Sdavidcs{
969252206Sdavidcs	uint32_t data32;
970252206Sdavidcs	uint32_t count = 3;
971252206Sdavidcs
972252206Sdavidcs	while (count--) {
973252206Sdavidcs
974252206Sdavidcs		data32 = READ_REG32(ha, Q81_CTL_CONFIG);
975252206Sdavidcs
976252206Sdavidcs		if ((data32 & bits) == value)
977252206Sdavidcs			return (0);
978252206Sdavidcs
979252206Sdavidcs		QLA_USEC_DELAY(100);
980252206Sdavidcs	}
981252206Sdavidcs	ha->qla_initiate_recovery = 1;
982252206Sdavidcs	device_printf(ha->pci_dev, "%s: failed\n", __func__);
983252206Sdavidcs	return (-1);
984252206Sdavidcs}
985252206Sdavidcs
986252206Sdavidcsstatic uint8_t q81_hash_key[] = {
987252206Sdavidcs			0xda, 0x56, 0x5a, 0x6d,
988252206Sdavidcs			0xc2, 0x0e, 0x5b, 0x25,
989252206Sdavidcs			0x3d, 0x25, 0x67, 0x41,
990252206Sdavidcs			0xb0, 0x8f, 0xa3, 0x43,
991252206Sdavidcs			0xcb, 0x2b, 0xca, 0xd0,
992252206Sdavidcs			0xb4, 0x30, 0x7b, 0xae,
993252206Sdavidcs			0xa3, 0x2d, 0xcb, 0x77,
994252206Sdavidcs			0x0c, 0xf2, 0x30, 0x80,
995252206Sdavidcs			0x3b, 0xb7, 0x42, 0x6a,
996252206Sdavidcs			0xfa, 0x01, 0xac, 0xbe };
997252206Sdavidcs
998252206Sdavidcsstatic int
999252206Sdavidcsqls_init_rss(qla_host_t *ha)
1000252206Sdavidcs{
1001252206Sdavidcs	q81_rss_icb_t	*rss_icb;
1002252206Sdavidcs	int		ret = 0;
1003252206Sdavidcs	int		i;
1004252206Sdavidcs	uint32_t	value;
1005252206Sdavidcs
1006252206Sdavidcs	rss_icb = ha->rss_dma.dma_b;
1007252206Sdavidcs
1008252206Sdavidcs	bzero(rss_icb, sizeof (q81_rss_icb_t));
1009252206Sdavidcs
1010252206Sdavidcs	rss_icb->flags_base_cq_num = Q81_RSS_ICB_FLAGS_L4K |
1011252206Sdavidcs				Q81_RSS_ICB_FLAGS_L6K | Q81_RSS_ICB_FLAGS_LI |
1012252206Sdavidcs				Q81_RSS_ICB_FLAGS_LB | Q81_RSS_ICB_FLAGS_LM |
1013252206Sdavidcs				Q81_RSS_ICB_FLAGS_RT4 | Q81_RSS_ICB_FLAGS_RT6;
1014252206Sdavidcs
1015252206Sdavidcs	rss_icb->mask = 0x3FF;
1016252206Sdavidcs
1017252206Sdavidcs	for (i = 0; i < Q81_RSS_ICB_NUM_INDTBL_ENTRIES; i++) {
1018252206Sdavidcs		rss_icb->cq_id[i] = (i & (ha->num_rx_rings - 1));
1019252206Sdavidcs	}
1020252206Sdavidcs
1021252206Sdavidcs	memcpy(rss_icb->ipv6_rss_hash_key, q81_hash_key, 40);
1022252206Sdavidcs	memcpy(rss_icb->ipv4_rss_hash_key, q81_hash_key, 16);
1023252206Sdavidcs
1024252206Sdavidcs	ret = qls_wait_for_config_reg_bits(ha, Q81_CTL_CONFIG_LR, 0);
1025252206Sdavidcs
1026252206Sdavidcs	if (ret)
1027252206Sdavidcs		goto qls_init_rss_exit;
1028252206Sdavidcs
1029252206Sdavidcs	ret = qls_sem_lock(ha, Q81_CTL_SEM_MASK_ICB, Q81_CTL_SEM_SET_ICB);
1030252206Sdavidcs
1031252206Sdavidcs	if (ret) {
1032252206Sdavidcs		QL_DPRINT1((ha->pci_dev, "%s: semlock failed\n", __func__));
1033252206Sdavidcs		goto qls_init_rss_exit;
1034252206Sdavidcs	}
1035252206Sdavidcs
1036252206Sdavidcs	value = (uint32_t)ha->rss_dma.dma_addr;
1037252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_ICB_ACCESS_ADDR_LO, value);
1038252206Sdavidcs
1039252206Sdavidcs	value = (uint32_t)(ha->rss_dma.dma_addr >> 32);
1040252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_ICB_ACCESS_ADDR_HI, value);
1041252206Sdavidcs
1042252206Sdavidcs	qls_sem_unlock(ha, Q81_CTL_SEM_MASK_ICB);
1043252206Sdavidcs
1044252206Sdavidcs	value = (Q81_CTL_CONFIG_LR << Q81_CTL_CONFIG_MASK_SHIFT) |
1045252206Sdavidcs			Q81_CTL_CONFIG_LR;
1046252206Sdavidcs
1047252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_CONFIG, value);
1048252206Sdavidcs
1049252206Sdavidcs	ret = qls_wait_for_config_reg_bits(ha, Q81_CTL_CONFIG_LR, 0);
1050252206Sdavidcs
1051252206Sdavidcsqls_init_rss_exit:
1052252206Sdavidcs	return (ret);
1053252206Sdavidcs}
1054252206Sdavidcs
1055252206Sdavidcsstatic int
1056252206Sdavidcsqls_init_comp_queue(qla_host_t *ha, int cid)
1057252206Sdavidcs{
1058252206Sdavidcs	q81_cq_icb_t	*cq_icb;
1059252206Sdavidcs	qla_rx_ring_t	*rxr;
1060252206Sdavidcs	int		ret = 0;
1061252206Sdavidcs	uint32_t	value;
1062252206Sdavidcs
1063252206Sdavidcs	rxr = &ha->rx_ring[cid];
1064252206Sdavidcs
1065252206Sdavidcs	rxr->cq_db_offset = ha->vm_pgsize * (128 + cid);
1066252206Sdavidcs
1067252206Sdavidcs	cq_icb = rxr->cq_icb_vaddr;
1068252206Sdavidcs
1069252206Sdavidcs	bzero(cq_icb, sizeof (q81_cq_icb_t));
1070252206Sdavidcs
1071252206Sdavidcs	cq_icb->msix_vector = cid;
1072252206Sdavidcs	cq_icb->flags = Q81_CQ_ICB_FLAGS_LC |
1073252206Sdavidcs			Q81_CQ_ICB_FLAGS_LI |
1074252206Sdavidcs			Q81_CQ_ICB_FLAGS_LL |
1075252206Sdavidcs			Q81_CQ_ICB_FLAGS_LS |
1076252206Sdavidcs			Q81_CQ_ICB_FLAGS_LV;
1077252206Sdavidcs
1078252206Sdavidcs	cq_icb->length_v = NUM_CQ_ENTRIES;
1079252206Sdavidcs
1080252206Sdavidcs	cq_icb->cq_baddr_lo = (rxr->cq_base_paddr & 0xFFFFFFFF);
1081252206Sdavidcs	cq_icb->cq_baddr_hi = (rxr->cq_base_paddr >> 32) & 0xFFFFFFFF;
1082252206Sdavidcs
1083252206Sdavidcs	cq_icb->cqi_addr_lo = (rxr->cqi_paddr & 0xFFFFFFFF);
1084252206Sdavidcs	cq_icb->cqi_addr_hi = (rxr->cqi_paddr >> 32) & 0xFFFFFFFF;
1085252206Sdavidcs
1086252206Sdavidcs	cq_icb->pkt_idelay = 10;
1087252206Sdavidcs	cq_icb->idelay = 100;
1088252206Sdavidcs
1089252206Sdavidcs	cq_icb->lbq_baddr_lo = (rxr->lbq_addr_tbl_paddr & 0xFFFFFFFF);
1090252206Sdavidcs	cq_icb->lbq_baddr_hi = (rxr->lbq_addr_tbl_paddr >> 32) & 0xFFFFFFFF;
1091252206Sdavidcs
1092252206Sdavidcs	cq_icb->lbq_bsize = QLA_LGB_SIZE;
1093252206Sdavidcs	cq_icb->lbq_length = QLA_NUM_LGB_ENTRIES;
1094252206Sdavidcs
1095252206Sdavidcs	cq_icb->sbq_baddr_lo = (rxr->sbq_addr_tbl_paddr & 0xFFFFFFFF);
1096252206Sdavidcs	cq_icb->sbq_baddr_hi = (rxr->sbq_addr_tbl_paddr >> 32) & 0xFFFFFFFF;
1097252206Sdavidcs
1098252206Sdavidcs	cq_icb->sbq_bsize = (uint16_t)ha->msize;
1099252206Sdavidcs	cq_icb->sbq_length = QLA_NUM_SMB_ENTRIES;
1100252206Sdavidcs
1101252206Sdavidcs	QL_DUMP_CQ(ha);
1102252206Sdavidcs
1103252206Sdavidcs	ret = qls_wait_for_config_reg_bits(ha, Q81_CTL_CONFIG_LCQ, 0);
1104252206Sdavidcs
1105252206Sdavidcs	if (ret)
1106252206Sdavidcs		goto qls_init_comp_queue_exit;
1107252206Sdavidcs
1108252206Sdavidcs	ret = qls_sem_lock(ha, Q81_CTL_SEM_MASK_ICB, Q81_CTL_SEM_SET_ICB);
1109252206Sdavidcs
1110252206Sdavidcs	if (ret) {
1111252206Sdavidcs		QL_DPRINT1((ha->pci_dev, "%s: semlock failed\n", __func__));
1112252206Sdavidcs		goto qls_init_comp_queue_exit;
1113252206Sdavidcs	}
1114252206Sdavidcs
1115252206Sdavidcs	value = (uint32_t)rxr->cq_icb_paddr;
1116252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_ICB_ACCESS_ADDR_LO, value);
1117252206Sdavidcs
1118252206Sdavidcs	value = (uint32_t)(rxr->cq_icb_paddr >> 32);
1119252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_ICB_ACCESS_ADDR_HI, value);
1120252206Sdavidcs
1121252206Sdavidcs	qls_sem_unlock(ha, Q81_CTL_SEM_MASK_ICB);
1122252206Sdavidcs
1123252206Sdavidcs	value = Q81_CTL_CONFIG_LCQ | Q81_CTL_CONFIG_Q_NUM_MASK;
1124252206Sdavidcs	value = (value << Q81_CTL_CONFIG_MASK_SHIFT) | Q81_CTL_CONFIG_LCQ;
1125252206Sdavidcs	value |= (cid << Q81_CTL_CONFIG_Q_NUM_SHIFT);
1126252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_CONFIG, value);
1127252206Sdavidcs
1128252206Sdavidcs	ret = qls_wait_for_config_reg_bits(ha, Q81_CTL_CONFIG_LCQ, 0);
1129252206Sdavidcs
1130252206Sdavidcs	rxr->cq_next = 0;
1131252206Sdavidcs	rxr->lbq_next = rxr->lbq_free = 0;
1132252206Sdavidcs	rxr->sbq_next = rxr->sbq_free = 0;
1133252206Sdavidcs	rxr->rx_free = rxr->rx_next = 0;
1134252206Sdavidcs	rxr->lbq_in = (QLA_NUM_LGB_ENTRIES - 1) & ~0xF;
1135252206Sdavidcs	rxr->sbq_in = (QLA_NUM_SMB_ENTRIES - 1) & ~0xF;
1136252206Sdavidcs
1137252206Sdavidcsqls_init_comp_queue_exit:
1138252206Sdavidcs	return (ret);
1139252206Sdavidcs}
1140252206Sdavidcs
1141252206Sdavidcsstatic int
1142252206Sdavidcsqls_init_work_queue(qla_host_t *ha, int wid)
1143252206Sdavidcs{
1144252206Sdavidcs	q81_wq_icb_t	*wq_icb;
1145252206Sdavidcs	qla_tx_ring_t	*txr;
1146252206Sdavidcs	int		ret = 0;
1147252206Sdavidcs	uint32_t	value;
1148252206Sdavidcs
1149252206Sdavidcs	txr = &ha->tx_ring[wid];
1150252206Sdavidcs
1151252206Sdavidcs	txr->wq_db_addr = (struct resource *)((uint8_t *)ha->pci_reg1
1152252206Sdavidcs						+ (ha->vm_pgsize * wid));
1153252206Sdavidcs
1154252206Sdavidcs	txr->wq_db_offset = (ha->vm_pgsize * wid);
1155252206Sdavidcs
1156252206Sdavidcs	wq_icb = txr->wq_icb_vaddr;
1157252206Sdavidcs	bzero(wq_icb, sizeof (q81_wq_icb_t));
1158252206Sdavidcs
1159252206Sdavidcs	wq_icb->length_v = NUM_TX_DESCRIPTORS  |
1160252206Sdavidcs				Q81_WQ_ICB_VALID;
1161252206Sdavidcs
1162252206Sdavidcs	wq_icb->flags = Q81_WQ_ICB_FLAGS_LO | Q81_WQ_ICB_FLAGS_LI |
1163252206Sdavidcs			Q81_WQ_ICB_FLAGS_LB | Q81_WQ_ICB_FLAGS_LC;
1164252206Sdavidcs
1165252206Sdavidcs	wq_icb->wqcqid_rss = wid;
1166252206Sdavidcs
1167252206Sdavidcs	wq_icb->baddr_lo = txr->wq_paddr & 0xFFFFFFFF;
1168252206Sdavidcs	wq_icb->baddr_hi = (txr->wq_paddr >> 32)& 0xFFFFFFFF;
1169252206Sdavidcs
1170252206Sdavidcs	wq_icb->ci_addr_lo = txr->txr_cons_paddr & 0xFFFFFFFF;
1171252206Sdavidcs	wq_icb->ci_addr_hi = (txr->txr_cons_paddr >> 32)& 0xFFFFFFFF;
1172252206Sdavidcs
1173252206Sdavidcs	ret = qls_wait_for_config_reg_bits(ha, Q81_CTL_CONFIG_LRQ, 0);
1174252206Sdavidcs
1175252206Sdavidcs	if (ret)
1176252206Sdavidcs		goto qls_init_wq_exit;
1177252206Sdavidcs
1178252206Sdavidcs	ret = qls_sem_lock(ha, Q81_CTL_SEM_MASK_ICB, Q81_CTL_SEM_SET_ICB);
1179252206Sdavidcs
1180252206Sdavidcs	if (ret) {
1181252206Sdavidcs		QL_DPRINT1((ha->pci_dev, "%s: semlock failed\n", __func__));
1182252206Sdavidcs		goto qls_init_wq_exit;
1183252206Sdavidcs	}
1184252206Sdavidcs
1185252206Sdavidcs	value = (uint32_t)txr->wq_icb_paddr;
1186252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_ICB_ACCESS_ADDR_LO, value);
1187252206Sdavidcs
1188252206Sdavidcs	value = (uint32_t)(txr->wq_icb_paddr >> 32);
1189252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_ICB_ACCESS_ADDR_HI, value);
1190252206Sdavidcs
1191252206Sdavidcs	qls_sem_unlock(ha, Q81_CTL_SEM_MASK_ICB);
1192252206Sdavidcs
1193252206Sdavidcs	value = Q81_CTL_CONFIG_LRQ | Q81_CTL_CONFIG_Q_NUM_MASK;
1194252206Sdavidcs	value = (value << Q81_CTL_CONFIG_MASK_SHIFT) | Q81_CTL_CONFIG_LRQ;
1195252206Sdavidcs	value |= (wid << Q81_CTL_CONFIG_Q_NUM_SHIFT);
1196252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_CONFIG, value);
1197252206Sdavidcs
1198252206Sdavidcs	ret = qls_wait_for_config_reg_bits(ha, Q81_CTL_CONFIG_LRQ, 0);
1199252206Sdavidcs
1200252206Sdavidcs	txr->txr_free = NUM_TX_DESCRIPTORS;
1201252206Sdavidcs	txr->txr_next = 0;
1202252206Sdavidcs	txr->txr_done = 0;
1203252206Sdavidcs
1204252206Sdavidcsqls_init_wq_exit:
1205252206Sdavidcs	return (ret);
1206252206Sdavidcs}
1207252206Sdavidcs
1208252206Sdavidcsstatic int
1209252206Sdavidcsqls_hw_add_all_mcast(qla_host_t *ha)
1210252206Sdavidcs{
1211252206Sdavidcs	int i, nmcast;
1212252206Sdavidcs
1213252206Sdavidcs	nmcast = ha->nmcast;
1214252206Sdavidcs
1215252206Sdavidcs	for (i = 0 ; ((i < Q8_MAX_NUM_MULTICAST_ADDRS) && nmcast); i++) {
1216252206Sdavidcs		if ((ha->mcast[i].addr[0] != 0) ||
1217252206Sdavidcs			(ha->mcast[i].addr[1] != 0) ||
1218252206Sdavidcs			(ha->mcast[i].addr[2] != 0) ||
1219252206Sdavidcs			(ha->mcast[i].addr[3] != 0) ||
1220252206Sdavidcs			(ha->mcast[i].addr[4] != 0) ||
1221252206Sdavidcs			(ha->mcast[i].addr[5] != 0)) {
1222252206Sdavidcs
1223252206Sdavidcs			if (qls_config_mcast_mac_addr(ha, ha->mcast[i].addr,
1224252206Sdavidcs				1, i)) {
1225252206Sdavidcs                		device_printf(ha->pci_dev, "%s: failed\n",
1226252206Sdavidcs					__func__);
1227252206Sdavidcs				return (-1);
1228252206Sdavidcs			}
1229252206Sdavidcs
1230252206Sdavidcs			nmcast--;
1231252206Sdavidcs		}
1232252206Sdavidcs	}
1233252206Sdavidcs	return 0;
1234252206Sdavidcs}
1235252206Sdavidcs
1236252206Sdavidcsstatic int
1237252206Sdavidcsqls_hw_add_mcast(qla_host_t *ha, uint8_t *mta)
1238252206Sdavidcs{
1239252206Sdavidcs	int i;
1240252206Sdavidcs
1241252206Sdavidcs	for (i = 0; i < Q8_MAX_NUM_MULTICAST_ADDRS; i++) {
1242252206Sdavidcs
1243252206Sdavidcs		if (QL_MAC_CMP(ha->mcast[i].addr, mta) == 0)
1244252206Sdavidcs			return 0; /* its been already added */
1245252206Sdavidcs	}
1246252206Sdavidcs
1247252206Sdavidcs	for (i = 0; i < Q8_MAX_NUM_MULTICAST_ADDRS; i++) {
1248252206Sdavidcs
1249252206Sdavidcs		if ((ha->mcast[i].addr[0] == 0) &&
1250252206Sdavidcs			(ha->mcast[i].addr[1] == 0) &&
1251252206Sdavidcs			(ha->mcast[i].addr[2] == 0) &&
1252252206Sdavidcs			(ha->mcast[i].addr[3] == 0) &&
1253252206Sdavidcs			(ha->mcast[i].addr[4] == 0) &&
1254252206Sdavidcs			(ha->mcast[i].addr[5] == 0)) {
1255252206Sdavidcs
1256252206Sdavidcs			if (qls_config_mcast_mac_addr(ha, mta, 1, i))
1257252206Sdavidcs				return (-1);
1258252206Sdavidcs
1259252206Sdavidcs			bcopy(mta, ha->mcast[i].addr, Q8_MAC_ADDR_LEN);
1260252206Sdavidcs			ha->nmcast++;
1261252206Sdavidcs
1262252206Sdavidcs			return 0;
1263252206Sdavidcs		}
1264252206Sdavidcs	}
1265252206Sdavidcs	return 0;
1266252206Sdavidcs}
1267252206Sdavidcs
1268252206Sdavidcsstatic int
1269252206Sdavidcsqls_hw_del_mcast(qla_host_t *ha, uint8_t *mta)
1270252206Sdavidcs{
1271252206Sdavidcs	int i;
1272252206Sdavidcs
1273252206Sdavidcs	for (i = 0; i < Q8_MAX_NUM_MULTICAST_ADDRS; i++) {
1274252206Sdavidcs		if (QL_MAC_CMP(ha->mcast[i].addr, mta) == 0) {
1275252206Sdavidcs
1276252206Sdavidcs			if (qls_config_mcast_mac_addr(ha, mta, 0, i))
1277252206Sdavidcs				return (-1);
1278252206Sdavidcs
1279252206Sdavidcs			ha->mcast[i].addr[0] = 0;
1280252206Sdavidcs			ha->mcast[i].addr[1] = 0;
1281252206Sdavidcs			ha->mcast[i].addr[2] = 0;
1282252206Sdavidcs			ha->mcast[i].addr[3] = 0;
1283252206Sdavidcs			ha->mcast[i].addr[4] = 0;
1284252206Sdavidcs			ha->mcast[i].addr[5] = 0;
1285252206Sdavidcs
1286252206Sdavidcs			ha->nmcast--;
1287252206Sdavidcs
1288252206Sdavidcs			return 0;
1289252206Sdavidcs		}
1290252206Sdavidcs	}
1291252206Sdavidcs	return 0;
1292252206Sdavidcs}
1293252206Sdavidcs
1294252206Sdavidcs/*
1295252206Sdavidcs * Name: qls_hw_set_multi
1296252206Sdavidcs * Function: Sets the Multicast Addresses provided the host O.S into the
1297252206Sdavidcs *	hardware (for the given interface)
1298252206Sdavidcs */
1299252206Sdavidcsvoid
1300252206Sdavidcsqls_hw_set_multi(qla_host_t *ha, uint8_t *mta, uint32_t mcnt,
1301252206Sdavidcs	uint32_t add_mac)
1302252206Sdavidcs{
1303252206Sdavidcs	int i;
1304252206Sdavidcs
1305252206Sdavidcs	for (i = 0; i < mcnt; i++) {
1306252206Sdavidcs		if (add_mac) {
1307252206Sdavidcs			if (qls_hw_add_mcast(ha, mta))
1308252206Sdavidcs				break;
1309252206Sdavidcs		} else {
1310252206Sdavidcs			if (qls_hw_del_mcast(ha, mta))
1311252206Sdavidcs				break;
1312252206Sdavidcs		}
1313252206Sdavidcs
1314252206Sdavidcs		mta += Q8_MAC_ADDR_LEN;
1315252206Sdavidcs	}
1316252206Sdavidcs	return;
1317252206Sdavidcs}
1318252206Sdavidcs
1319252206Sdavidcsvoid
1320252206Sdavidcsqls_update_link_state(qla_host_t *ha)
1321252206Sdavidcs{
1322252206Sdavidcs	uint32_t link_state;
1323252206Sdavidcs	uint32_t prev_link_state;
1324252206Sdavidcs
1325252206Sdavidcs	if (!(ha->ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1326252206Sdavidcs		ha->link_up = 0;
1327252206Sdavidcs		return;
1328252206Sdavidcs	}
1329252206Sdavidcs	link_state = READ_REG32(ha, Q81_CTL_STATUS);
1330252206Sdavidcs
1331252206Sdavidcs	prev_link_state =  ha->link_up;
1332252206Sdavidcs
1333252206Sdavidcs	if ((ha->pci_func & 0x1) == 0)
1334252206Sdavidcs		ha->link_up = ((link_state & Q81_CTL_STATUS_PL0)? 1 : 0);
1335252206Sdavidcs	else
1336252206Sdavidcs		ha->link_up = ((link_state & Q81_CTL_STATUS_PL1)? 1 : 0);
1337252206Sdavidcs
1338252206Sdavidcs	if (prev_link_state !=  ha->link_up) {
1339252206Sdavidcs
1340252206Sdavidcs
1341252206Sdavidcs		if (ha->link_up) {
1342252206Sdavidcs			if_link_state_change(ha->ifp, LINK_STATE_UP);
1343252206Sdavidcs		} else {
1344252206Sdavidcs			if_link_state_change(ha->ifp, LINK_STATE_DOWN);
1345252206Sdavidcs		}
1346252206Sdavidcs	}
1347252206Sdavidcs	return;
1348252206Sdavidcs}
1349252206Sdavidcs
1350252206Sdavidcsstatic void
1351252206Sdavidcsqls_free_tx_ring_dma(qla_host_t *ha, int r_idx)
1352252206Sdavidcs{
1353252206Sdavidcs	if (ha->tx_ring[r_idx].flags.wq_dma) {
1354252206Sdavidcs		qls_free_dmabuf(ha, &ha->tx_ring[r_idx].wq_dma);
1355252206Sdavidcs		ha->tx_ring[r_idx].flags.wq_dma = 0;
1356252206Sdavidcs	}
1357252206Sdavidcs
1358252206Sdavidcs	if (ha->tx_ring[r_idx].flags.privb_dma) {
1359252206Sdavidcs		qls_free_dmabuf(ha, &ha->tx_ring[r_idx].privb_dma);
1360252206Sdavidcs		ha->tx_ring[r_idx].flags.privb_dma = 0;
1361252206Sdavidcs	}
1362252206Sdavidcs	return;
1363252206Sdavidcs}
1364252206Sdavidcs
1365252206Sdavidcsstatic void
1366252206Sdavidcsqls_free_tx_dma(qla_host_t *ha)
1367252206Sdavidcs{
1368252206Sdavidcs	int i, j;
1369252206Sdavidcs	qla_tx_buf_t *txb;
1370252206Sdavidcs
1371252206Sdavidcs	for (i = 0; i < ha->num_tx_rings; i++) {
1372252206Sdavidcs
1373252206Sdavidcs		qls_free_tx_ring_dma(ha, i);
1374252206Sdavidcs
1375252206Sdavidcs		for (j = 0; j < NUM_TX_DESCRIPTORS; j++) {
1376252206Sdavidcs
1377252206Sdavidcs			txb = &ha->tx_ring[i].tx_buf[j];
1378252206Sdavidcs
1379252206Sdavidcs			if (txb->map) {
1380252206Sdavidcs				bus_dmamap_destroy(ha->tx_tag, txb->map);
1381252206Sdavidcs			}
1382252206Sdavidcs		}
1383252206Sdavidcs	}
1384252206Sdavidcs
1385252206Sdavidcs        if (ha->tx_tag != NULL) {
1386252206Sdavidcs                bus_dma_tag_destroy(ha->tx_tag);
1387252206Sdavidcs                ha->tx_tag = NULL;
1388252206Sdavidcs        }
1389252206Sdavidcs
1390252206Sdavidcs	return;
1391252206Sdavidcs}
1392252206Sdavidcs
1393252206Sdavidcsstatic int
1394252206Sdavidcsqls_alloc_tx_ring_dma(qla_host_t *ha, int ridx)
1395252206Sdavidcs{
1396252206Sdavidcs	int		ret = 0, i;
1397252206Sdavidcs	uint8_t		*v_addr;
1398252206Sdavidcs	bus_addr_t	p_addr;
1399252206Sdavidcs	qla_tx_buf_t	*txb;
1400252206Sdavidcs	device_t	dev = ha->pci_dev;
1401252206Sdavidcs
1402252206Sdavidcs	ha->tx_ring[ridx].wq_dma.alignment = 8;
1403252206Sdavidcs	ha->tx_ring[ridx].wq_dma.size =
1404252206Sdavidcs		NUM_TX_DESCRIPTORS * (sizeof (q81_tx_cmd_t));
1405252206Sdavidcs
1406252206Sdavidcs	ret = qls_alloc_dmabuf(ha, &ha->tx_ring[ridx].wq_dma);
1407252206Sdavidcs
1408252206Sdavidcs	if (ret) {
1409252206Sdavidcs		device_printf(dev, "%s: [%d] txr failed\n", __func__, ridx);
1410252206Sdavidcs		goto qls_alloc_tx_ring_dma_exit;
1411252206Sdavidcs	}
1412252206Sdavidcs	ha->tx_ring[ridx].flags.wq_dma = 1;
1413252206Sdavidcs
1414252206Sdavidcs	ha->tx_ring[ridx].privb_dma.alignment = 8;
1415252206Sdavidcs	ha->tx_ring[ridx].privb_dma.size = QLA_TX_PRIVATE_BSIZE;
1416252206Sdavidcs
1417252206Sdavidcs	ret = qls_alloc_dmabuf(ha, &ha->tx_ring[ridx].privb_dma);
1418252206Sdavidcs
1419252206Sdavidcs	if (ret) {
1420252206Sdavidcs		device_printf(dev, "%s: [%d] oalb failed\n", __func__, ridx);
1421252206Sdavidcs		goto qls_alloc_tx_ring_dma_exit;
1422252206Sdavidcs	}
1423252206Sdavidcs
1424252206Sdavidcs	ha->tx_ring[ridx].flags.privb_dma = 1;
1425252206Sdavidcs
1426252206Sdavidcs	ha->tx_ring[ridx].wq_vaddr = ha->tx_ring[ridx].wq_dma.dma_b;
1427252206Sdavidcs	ha->tx_ring[ridx].wq_paddr = ha->tx_ring[ridx].wq_dma.dma_addr;
1428252206Sdavidcs
1429252206Sdavidcs	v_addr = ha->tx_ring[ridx].privb_dma.dma_b;
1430252206Sdavidcs	p_addr = ha->tx_ring[ridx].privb_dma.dma_addr;
1431252206Sdavidcs
1432252206Sdavidcs	ha->tx_ring[ridx].wq_icb_vaddr = v_addr;
1433252206Sdavidcs	ha->tx_ring[ridx].wq_icb_paddr = p_addr;
1434252206Sdavidcs
1435252206Sdavidcs	ha->tx_ring[ridx].txr_cons_vaddr =
1436252206Sdavidcs		(uint32_t *)(v_addr + (PAGE_SIZE >> 1));
1437252206Sdavidcs	ha->tx_ring[ridx].txr_cons_paddr = p_addr + (PAGE_SIZE >> 1);
1438252206Sdavidcs
1439252206Sdavidcs	v_addr = v_addr + (PAGE_SIZE >> 1);
1440252206Sdavidcs	p_addr = p_addr + (PAGE_SIZE >> 1);
1441252206Sdavidcs
1442252206Sdavidcs	txb = ha->tx_ring[ridx].tx_buf;
1443252206Sdavidcs
1444252206Sdavidcs	for (i = 0; i < NUM_TX_DESCRIPTORS; i++) {
1445252206Sdavidcs
1446252206Sdavidcs		txb[i].oal_vaddr = v_addr;
1447252206Sdavidcs		txb[i].oal_paddr = p_addr;
1448252206Sdavidcs
1449252206Sdavidcs		v_addr = v_addr + QLA_OAL_BLK_SIZE;
1450252206Sdavidcs		p_addr = p_addr + QLA_OAL_BLK_SIZE;
1451252206Sdavidcs	}
1452252206Sdavidcs
1453252206Sdavidcsqls_alloc_tx_ring_dma_exit:
1454252206Sdavidcs	return (ret);
1455252206Sdavidcs}
1456252206Sdavidcs
1457252206Sdavidcsstatic int
1458252206Sdavidcsqls_alloc_tx_dma(qla_host_t *ha)
1459252206Sdavidcs{
1460252206Sdavidcs	int	i, j;
1461252206Sdavidcs	int	ret = 0;
1462252206Sdavidcs	qla_tx_buf_t *txb;
1463252206Sdavidcs
1464252206Sdavidcs        if (bus_dma_tag_create(NULL,    /* parent */
1465252206Sdavidcs                1, 0,    /* alignment, bounds */
1466252206Sdavidcs                BUS_SPACE_MAXADDR,       /* lowaddr */
1467252206Sdavidcs                BUS_SPACE_MAXADDR,       /* highaddr */
1468252206Sdavidcs                NULL, NULL,      /* filter, filterarg */
1469252206Sdavidcs                QLA_MAX_TSO_FRAME_SIZE,     /* maxsize */
1470252206Sdavidcs                QLA_MAX_SEGMENTS,        /* nsegments */
1471252206Sdavidcs                PAGE_SIZE,        /* maxsegsize */
1472252206Sdavidcs                BUS_DMA_ALLOCNOW,        /* flags */
1473252206Sdavidcs                NULL,    /* lockfunc */
1474252206Sdavidcs                NULL,    /* lockfuncarg */
1475252206Sdavidcs                &ha->tx_tag)) {
1476252206Sdavidcs                device_printf(ha->pci_dev, "%s: tx_tag alloc failed\n",
1477252206Sdavidcs                        __func__);
1478252206Sdavidcs                return (ENOMEM);
1479252206Sdavidcs        }
1480252206Sdavidcs
1481252206Sdavidcs	for (i = 0; i < ha->num_tx_rings; i++) {
1482252206Sdavidcs
1483252206Sdavidcs		ret = qls_alloc_tx_ring_dma(ha, i);
1484252206Sdavidcs
1485252206Sdavidcs		if (ret) {
1486252206Sdavidcs			qls_free_tx_dma(ha);
1487252206Sdavidcs			break;
1488252206Sdavidcs		}
1489252206Sdavidcs
1490252206Sdavidcs		for (j = 0; j < NUM_TX_DESCRIPTORS; j++) {
1491252206Sdavidcs
1492252206Sdavidcs			txb = &ha->tx_ring[i].tx_buf[j];
1493252206Sdavidcs
1494252206Sdavidcs			ret = bus_dmamap_create(ha->tx_tag,
1495252206Sdavidcs				BUS_DMA_NOWAIT, &txb->map);
1496252206Sdavidcs			if (ret) {
1497252206Sdavidcs				ha->err_tx_dmamap_create++;
1498252206Sdavidcs				device_printf(ha->pci_dev,
1499252206Sdavidcs				"%s: bus_dmamap_create failed[%d, %d, %d]\n",
1500252206Sdavidcs				__func__, ret, i, j);
1501252206Sdavidcs
1502252206Sdavidcs				qls_free_tx_dma(ha);
1503252206Sdavidcs
1504252206Sdavidcs                		return (ret);
1505252206Sdavidcs       			}
1506252206Sdavidcs		}
1507252206Sdavidcs	}
1508252206Sdavidcs
1509252206Sdavidcs	return (ret);
1510252206Sdavidcs}
1511252206Sdavidcs
1512252206Sdavidcsstatic void
1513252206Sdavidcsqls_free_rss_dma(qla_host_t *ha)
1514252206Sdavidcs{
1515252206Sdavidcs	qls_free_dmabuf(ha, &ha->rss_dma);
1516252206Sdavidcs	ha->flags.rss_dma = 0;
1517252206Sdavidcs}
1518252206Sdavidcs
1519252206Sdavidcsstatic int
1520252206Sdavidcsqls_alloc_rss_dma(qla_host_t *ha)
1521252206Sdavidcs{
1522252206Sdavidcs	int ret = 0;
1523252206Sdavidcs
1524252206Sdavidcs	ha->rss_dma.alignment = 4;
1525252206Sdavidcs	ha->rss_dma.size = PAGE_SIZE;
1526252206Sdavidcs
1527252206Sdavidcs	ret = qls_alloc_dmabuf(ha, &ha->rss_dma);
1528252206Sdavidcs
1529252206Sdavidcs	if (ret)
1530252206Sdavidcs		device_printf(ha->pci_dev, "%s: failed\n", __func__);
1531252206Sdavidcs	else
1532252206Sdavidcs		ha->flags.rss_dma = 1;
1533252206Sdavidcs
1534252206Sdavidcs	return (ret);
1535252206Sdavidcs}
1536252206Sdavidcs
1537252206Sdavidcsstatic void
1538252206Sdavidcsqls_free_mpi_dma(qla_host_t *ha)
1539252206Sdavidcs{
1540252206Sdavidcs	qls_free_dmabuf(ha, &ha->mpi_dma);
1541252206Sdavidcs	ha->flags.mpi_dma = 0;
1542252206Sdavidcs}
1543252206Sdavidcs
1544252206Sdavidcsstatic int
1545252206Sdavidcsqls_alloc_mpi_dma(qla_host_t *ha)
1546252206Sdavidcs{
1547252206Sdavidcs	int ret = 0;
1548252206Sdavidcs
1549252206Sdavidcs	ha->mpi_dma.alignment = 4;
1550252206Sdavidcs	ha->mpi_dma.size = (0x4000 * 4);
1551252206Sdavidcs
1552252206Sdavidcs	ret = qls_alloc_dmabuf(ha, &ha->mpi_dma);
1553252206Sdavidcs	if (ret)
1554252206Sdavidcs		device_printf(ha->pci_dev, "%s: failed\n", __func__);
1555252206Sdavidcs	else
1556252206Sdavidcs		ha->flags.mpi_dma = 1;
1557252206Sdavidcs
1558252206Sdavidcs	return (ret);
1559252206Sdavidcs}
1560252206Sdavidcs
1561252206Sdavidcsstatic void
1562252206Sdavidcsqls_free_rx_ring_dma(qla_host_t *ha, int ridx)
1563252206Sdavidcs{
1564252206Sdavidcs	if (ha->rx_ring[ridx].flags.cq_dma) {
1565252206Sdavidcs		qls_free_dmabuf(ha, &ha->rx_ring[ridx].cq_dma);
1566252206Sdavidcs		ha->rx_ring[ridx].flags.cq_dma = 0;
1567252206Sdavidcs	}
1568252206Sdavidcs
1569252206Sdavidcs	if (ha->rx_ring[ridx].flags.lbq_dma) {
1570252206Sdavidcs		qls_free_dmabuf(ha, &ha->rx_ring[ridx].lbq_dma);
1571252206Sdavidcs		ha->rx_ring[ridx].flags.lbq_dma = 0;
1572252206Sdavidcs	}
1573252206Sdavidcs
1574252206Sdavidcs	if (ha->rx_ring[ridx].flags.sbq_dma) {
1575252206Sdavidcs		qls_free_dmabuf(ha, &ha->rx_ring[ridx].sbq_dma);
1576252206Sdavidcs		ha->rx_ring[ridx].flags.sbq_dma = 0;
1577252206Sdavidcs	}
1578252206Sdavidcs
1579252206Sdavidcs	if (ha->rx_ring[ridx].flags.lb_dma) {
1580252206Sdavidcs		qls_free_dmabuf(ha, &ha->rx_ring[ridx].lb_dma);
1581252206Sdavidcs		ha->rx_ring[ridx].flags.lb_dma = 0;
1582252206Sdavidcs	}
1583252206Sdavidcs	return;
1584252206Sdavidcs}
1585252206Sdavidcs
1586252206Sdavidcsstatic void
1587252206Sdavidcsqls_free_rx_dma(qla_host_t *ha)
1588252206Sdavidcs{
1589252206Sdavidcs	int i;
1590252206Sdavidcs
1591252206Sdavidcs	for (i = 0; i < ha->num_rx_rings; i++) {
1592252206Sdavidcs		qls_free_rx_ring_dma(ha, i);
1593252206Sdavidcs	}
1594252206Sdavidcs
1595252206Sdavidcs        if (ha->rx_tag != NULL) {
1596252206Sdavidcs                bus_dma_tag_destroy(ha->rx_tag);
1597252206Sdavidcs                ha->rx_tag = NULL;
1598252206Sdavidcs        }
1599252206Sdavidcs
1600252206Sdavidcs	return;
1601252206Sdavidcs}
1602252206Sdavidcs
1603252206Sdavidcsstatic int
1604252206Sdavidcsqls_alloc_rx_ring_dma(qla_host_t *ha, int ridx)
1605252206Sdavidcs{
1606252206Sdavidcs	int				i, ret = 0;
1607252206Sdavidcs	uint8_t				*v_addr;
1608252206Sdavidcs	bus_addr_t			p_addr;
1609252206Sdavidcs	volatile q81_bq_addr_e_t	*bq_e;
1610252206Sdavidcs	device_t			dev = ha->pci_dev;
1611252206Sdavidcs
1612252206Sdavidcs	ha->rx_ring[ridx].cq_dma.alignment = 128;
1613252206Sdavidcs	ha->rx_ring[ridx].cq_dma.size =
1614252206Sdavidcs		(NUM_CQ_ENTRIES * (sizeof (q81_cq_e_t))) + PAGE_SIZE;
1615252206Sdavidcs
1616252206Sdavidcs	ret = qls_alloc_dmabuf(ha, &ha->rx_ring[ridx].cq_dma);
1617252206Sdavidcs
1618252206Sdavidcs	if (ret) {
1619252206Sdavidcs		device_printf(dev, "%s: [%d] cq failed\n", __func__, ridx);
1620252206Sdavidcs		goto qls_alloc_rx_ring_dma_exit;
1621252206Sdavidcs	}
1622252206Sdavidcs	ha->rx_ring[ridx].flags.cq_dma = 1;
1623252206Sdavidcs
1624252206Sdavidcs	ha->rx_ring[ridx].lbq_dma.alignment = 8;
1625252206Sdavidcs	ha->rx_ring[ridx].lbq_dma.size = QLA_LGBQ_AND_TABLE_SIZE;
1626252206Sdavidcs
1627252206Sdavidcs	ret = qls_alloc_dmabuf(ha, &ha->rx_ring[ridx].lbq_dma);
1628252206Sdavidcs
1629252206Sdavidcs	if (ret) {
1630252206Sdavidcs		device_printf(dev, "%s: [%d] lbq failed\n", __func__, ridx);
1631252206Sdavidcs		goto qls_alloc_rx_ring_dma_exit;
1632252206Sdavidcs	}
1633252206Sdavidcs	ha->rx_ring[ridx].flags.lbq_dma = 1;
1634252206Sdavidcs
1635252206Sdavidcs	ha->rx_ring[ridx].sbq_dma.alignment = 8;
1636252206Sdavidcs	ha->rx_ring[ridx].sbq_dma.size = QLA_SMBQ_AND_TABLE_SIZE;
1637252206Sdavidcs
1638252206Sdavidcs	ret = qls_alloc_dmabuf(ha, &ha->rx_ring[ridx].sbq_dma);
1639252206Sdavidcs
1640252206Sdavidcs	if (ret) {
1641252206Sdavidcs		device_printf(dev, "%s: [%d] sbq failed\n", __func__, ridx);
1642252206Sdavidcs		goto qls_alloc_rx_ring_dma_exit;
1643252206Sdavidcs	}
1644252206Sdavidcs	ha->rx_ring[ridx].flags.sbq_dma = 1;
1645252206Sdavidcs
1646252206Sdavidcs	ha->rx_ring[ridx].lb_dma.alignment = 8;
1647252206Sdavidcs	ha->rx_ring[ridx].lb_dma.size = (QLA_LGB_SIZE * QLA_NUM_LGB_ENTRIES);
1648252206Sdavidcs
1649252206Sdavidcs	ret = qls_alloc_dmabuf(ha, &ha->rx_ring[ridx].lb_dma);
1650252206Sdavidcs	if (ret) {
1651252206Sdavidcs		device_printf(dev, "%s: [%d] lb failed\n", __func__, ridx);
1652252206Sdavidcs		goto qls_alloc_rx_ring_dma_exit;
1653252206Sdavidcs	}
1654252206Sdavidcs	ha->rx_ring[ridx].flags.lb_dma = 1;
1655252206Sdavidcs
1656252206Sdavidcs	bzero(ha->rx_ring[ridx].cq_dma.dma_b, ha->rx_ring[ridx].cq_dma.size);
1657252206Sdavidcs	bzero(ha->rx_ring[ridx].lbq_dma.dma_b, ha->rx_ring[ridx].lbq_dma.size);
1658252206Sdavidcs	bzero(ha->rx_ring[ridx].sbq_dma.dma_b, ha->rx_ring[ridx].sbq_dma.size);
1659252206Sdavidcs	bzero(ha->rx_ring[ridx].lb_dma.dma_b, ha->rx_ring[ridx].lb_dma.size);
1660252206Sdavidcs
1661252206Sdavidcs	/* completion queue */
1662252206Sdavidcs	ha->rx_ring[ridx].cq_base_vaddr = ha->rx_ring[ridx].cq_dma.dma_b;
1663252206Sdavidcs	ha->rx_ring[ridx].cq_base_paddr = ha->rx_ring[ridx].cq_dma.dma_addr;
1664252206Sdavidcs
1665252206Sdavidcs	v_addr = ha->rx_ring[ridx].cq_dma.dma_b;
1666252206Sdavidcs	p_addr = ha->rx_ring[ridx].cq_dma.dma_addr;
1667252206Sdavidcs
1668252206Sdavidcs	v_addr = v_addr + (NUM_CQ_ENTRIES * (sizeof (q81_cq_e_t)));
1669252206Sdavidcs	p_addr = p_addr + (NUM_CQ_ENTRIES * (sizeof (q81_cq_e_t)));
1670252206Sdavidcs
1671252206Sdavidcs	/* completion queue icb */
1672252206Sdavidcs	ha->rx_ring[ridx].cq_icb_vaddr = v_addr;
1673252206Sdavidcs	ha->rx_ring[ridx].cq_icb_paddr = p_addr;
1674252206Sdavidcs
1675252206Sdavidcs	v_addr = v_addr + (PAGE_SIZE >> 2);
1676252206Sdavidcs	p_addr = p_addr + (PAGE_SIZE >> 2);
1677252206Sdavidcs
1678252206Sdavidcs	/* completion queue index register */
1679252206Sdavidcs	ha->rx_ring[ridx].cqi_vaddr = (uint32_t *)v_addr;
1680252206Sdavidcs	ha->rx_ring[ridx].cqi_paddr = p_addr;
1681252206Sdavidcs
1682252206Sdavidcs	v_addr = ha->rx_ring[ridx].lbq_dma.dma_b;
1683252206Sdavidcs	p_addr = ha->rx_ring[ridx].lbq_dma.dma_addr;
1684252206Sdavidcs
1685252206Sdavidcs	/* large buffer queue address table */
1686252206Sdavidcs	ha->rx_ring[ridx].lbq_addr_tbl_vaddr = v_addr;
1687252206Sdavidcs	ha->rx_ring[ridx].lbq_addr_tbl_paddr = p_addr;
1688252206Sdavidcs
1689252206Sdavidcs	/* large buffer queue */
1690252206Sdavidcs	ha->rx_ring[ridx].lbq_vaddr = v_addr + PAGE_SIZE;
1691252206Sdavidcs	ha->rx_ring[ridx].lbq_paddr = p_addr + PAGE_SIZE;
1692252206Sdavidcs
1693252206Sdavidcs	v_addr = ha->rx_ring[ridx].sbq_dma.dma_b;
1694252206Sdavidcs	p_addr = ha->rx_ring[ridx].sbq_dma.dma_addr;
1695252206Sdavidcs
1696252206Sdavidcs	/* small buffer queue address table */
1697252206Sdavidcs	ha->rx_ring[ridx].sbq_addr_tbl_vaddr = v_addr;
1698252206Sdavidcs	ha->rx_ring[ridx].sbq_addr_tbl_paddr = p_addr;
1699252206Sdavidcs
1700252206Sdavidcs	/* small buffer queue */
1701252206Sdavidcs	ha->rx_ring[ridx].sbq_vaddr = v_addr + PAGE_SIZE;
1702252206Sdavidcs	ha->rx_ring[ridx].sbq_paddr = p_addr + PAGE_SIZE;
1703252206Sdavidcs
1704252206Sdavidcs	ha->rx_ring[ridx].lb_vaddr = ha->rx_ring[ridx].lb_dma.dma_b;
1705252206Sdavidcs	ha->rx_ring[ridx].lb_paddr = ha->rx_ring[ridx].lb_dma.dma_addr;
1706252206Sdavidcs
1707252206Sdavidcs	/* Initialize Large Buffer Queue Table */
1708252206Sdavidcs
1709252206Sdavidcs	p_addr = ha->rx_ring[ridx].lbq_paddr;
1710252206Sdavidcs	bq_e = ha->rx_ring[ridx].lbq_addr_tbl_vaddr;
1711252206Sdavidcs
1712252206Sdavidcs	bq_e->addr_lo = p_addr & 0xFFFFFFFF;
1713252206Sdavidcs	bq_e->addr_hi = (p_addr >> 32) & 0xFFFFFFFF;
1714252206Sdavidcs
1715252206Sdavidcs	p_addr = ha->rx_ring[ridx].lb_paddr;
1716252206Sdavidcs	bq_e = ha->rx_ring[ridx].lbq_vaddr;
1717252206Sdavidcs
1718252206Sdavidcs	for (i = 0; i < QLA_NUM_LGB_ENTRIES; i++) {
1719252206Sdavidcs		bq_e->addr_lo = p_addr & 0xFFFFFFFF;
1720252206Sdavidcs		bq_e->addr_hi = (p_addr >> 32) & 0xFFFFFFFF;
1721252206Sdavidcs
1722252206Sdavidcs		p_addr = p_addr + QLA_LGB_SIZE;
1723252206Sdavidcs		bq_e++;
1724252206Sdavidcs	}
1725252206Sdavidcs
1726252206Sdavidcs	/* Initialize Small Buffer Queue Table */
1727252206Sdavidcs
1728252206Sdavidcs	p_addr = ha->rx_ring[ridx].sbq_paddr;
1729252206Sdavidcs	bq_e = ha->rx_ring[ridx].sbq_addr_tbl_vaddr;
1730252206Sdavidcs
1731252206Sdavidcs	for (i =0; i < (QLA_SBQ_SIZE/QLA_PAGE_SIZE); i++) {
1732252206Sdavidcs		bq_e->addr_lo = p_addr & 0xFFFFFFFF;
1733252206Sdavidcs		bq_e->addr_hi = (p_addr >> 32) & 0xFFFFFFFF;
1734252206Sdavidcs
1735252206Sdavidcs		p_addr = p_addr + QLA_PAGE_SIZE;
1736252206Sdavidcs		bq_e++;
1737252206Sdavidcs	}
1738252206Sdavidcs
1739252206Sdavidcsqls_alloc_rx_ring_dma_exit:
1740252206Sdavidcs	return (ret);
1741252206Sdavidcs}
1742252206Sdavidcs
1743252206Sdavidcsstatic int
1744252206Sdavidcsqls_alloc_rx_dma(qla_host_t *ha)
1745252206Sdavidcs{
1746252206Sdavidcs	int	i;
1747252206Sdavidcs	int	ret = 0;
1748252206Sdavidcs
1749252206Sdavidcs        if (bus_dma_tag_create(NULL,    /* parent */
1750252206Sdavidcs                        1, 0,    /* alignment, bounds */
1751252206Sdavidcs                        BUS_SPACE_MAXADDR,       /* lowaddr */
1752252206Sdavidcs                        BUS_SPACE_MAXADDR,       /* highaddr */
1753252206Sdavidcs                        NULL, NULL,      /* filter, filterarg */
1754252206Sdavidcs                        MJUM9BYTES,     /* maxsize */
1755252206Sdavidcs                        1,        /* nsegments */
1756252206Sdavidcs                        MJUM9BYTES,        /* maxsegsize */
1757252206Sdavidcs                        BUS_DMA_ALLOCNOW,        /* flags */
1758252206Sdavidcs                        NULL,    /* lockfunc */
1759252206Sdavidcs                        NULL,    /* lockfuncarg */
1760252206Sdavidcs                        &ha->rx_tag)) {
1761252206Sdavidcs
1762252206Sdavidcs                device_printf(ha->pci_dev, "%s: rx_tag alloc failed\n",
1763252206Sdavidcs                        __func__);
1764252206Sdavidcs
1765252206Sdavidcs                return (ENOMEM);
1766252206Sdavidcs        }
1767252206Sdavidcs
1768252206Sdavidcs	for (i = 0; i < ha->num_rx_rings; i++) {
1769252206Sdavidcs		ret = qls_alloc_rx_ring_dma(ha, i);
1770252206Sdavidcs
1771252206Sdavidcs		if (ret) {
1772252206Sdavidcs			qls_free_rx_dma(ha);
1773252206Sdavidcs			break;
1774252206Sdavidcs		}
1775252206Sdavidcs	}
1776252206Sdavidcs
1777252206Sdavidcs	return (ret);
1778252206Sdavidcs}
1779252206Sdavidcs
1780252206Sdavidcsstatic int
1781252206Sdavidcsqls_wait_for_flash_ready(qla_host_t *ha)
1782252206Sdavidcs{
1783252206Sdavidcs	uint32_t data32;
1784252206Sdavidcs	uint32_t count = 3;
1785252206Sdavidcs
1786252206Sdavidcs	while (count--) {
1787252206Sdavidcs
1788252206Sdavidcs		data32 = READ_REG32(ha, Q81_CTL_FLASH_ADDR);
1789252206Sdavidcs
1790252206Sdavidcs		if (data32 & Q81_CTL_FLASH_ADDR_ERR)
1791252206Sdavidcs			goto qls_wait_for_flash_ready_exit;
1792252206Sdavidcs
1793252206Sdavidcs		if (data32 & Q81_CTL_FLASH_ADDR_RDY)
1794252206Sdavidcs			return (0);
1795252206Sdavidcs
1796252206Sdavidcs		QLA_USEC_DELAY(100);
1797252206Sdavidcs	}
1798252206Sdavidcs
1799252206Sdavidcsqls_wait_for_flash_ready_exit:
1800252206Sdavidcs	QL_DPRINT1((ha->pci_dev, "%s: failed\n", __func__));
1801252206Sdavidcs
1802252206Sdavidcs	return (-1);
1803252206Sdavidcs}
1804252206Sdavidcs
1805252206Sdavidcs/*
1806252206Sdavidcs * Name: qls_rd_flash32
1807252206Sdavidcs * Function: Read Flash Memory
1808252206Sdavidcs */
1809252206Sdavidcsint
1810252206Sdavidcsqls_rd_flash32(qla_host_t *ha, uint32_t addr, uint32_t *data)
1811252206Sdavidcs{
1812252206Sdavidcs	int ret;
1813252206Sdavidcs
1814252206Sdavidcs	ret = qls_wait_for_flash_ready(ha);
1815252206Sdavidcs
1816252206Sdavidcs	if (ret)
1817252206Sdavidcs		return (ret);
1818252206Sdavidcs
1819252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_FLASH_ADDR, (addr | Q81_CTL_FLASH_ADDR_R));
1820252206Sdavidcs
1821252206Sdavidcs	ret = qls_wait_for_flash_ready(ha);
1822252206Sdavidcs
1823252206Sdavidcs	if (ret)
1824252206Sdavidcs		return (ret);
1825252206Sdavidcs
1826252206Sdavidcs	*data = READ_REG32(ha, Q81_CTL_FLASH_DATA);
1827252206Sdavidcs
1828252206Sdavidcs	return 0;
1829252206Sdavidcs}
1830252206Sdavidcs
1831252206Sdavidcsstatic int
1832252206Sdavidcsqls_flash_validate(qla_host_t *ha, const char *signature)
1833252206Sdavidcs{
1834252206Sdavidcs	uint16_t csum16 = 0;
1835252206Sdavidcs	uint16_t *data16;
1836252206Sdavidcs	int i;
1837252206Sdavidcs
1838252206Sdavidcs	if (bcmp(ha->flash.id, signature, 4)) {
1839252206Sdavidcs		QL_DPRINT1((ha->pci_dev, "%s: invalid signature "
1840252206Sdavidcs			"%x:%x:%x:%x %s\n", __func__, ha->flash.id[0],
1841252206Sdavidcs			ha->flash.id[1], ha->flash.id[2], ha->flash.id[3],
1842252206Sdavidcs			signature));
1843252206Sdavidcs		return(-1);
1844252206Sdavidcs	}
1845252206Sdavidcs
1846252206Sdavidcs	data16 = (uint16_t *)&ha->flash;
1847252206Sdavidcs
1848252206Sdavidcs	for (i = 0; i < (sizeof (q81_flash_t) >> 1); i++) {
1849252206Sdavidcs		csum16 += *data16++;
1850252206Sdavidcs	}
1851252206Sdavidcs
1852252206Sdavidcs	if (csum16) {
1853252206Sdavidcs		QL_DPRINT1((ha->pci_dev, "%s: invalid checksum\n", __func__));
1854252206Sdavidcs		return(-1);
1855252206Sdavidcs	}
1856252206Sdavidcs	return(0);
1857252206Sdavidcs}
1858252206Sdavidcs
1859252206Sdavidcsint
1860252206Sdavidcsqls_rd_nic_params(qla_host_t *ha)
1861252206Sdavidcs{
1862252206Sdavidcs	int		i, ret = 0;
1863252206Sdavidcs	uint32_t	faddr;
1864252206Sdavidcs	uint32_t	*qflash;
1865252206Sdavidcs
1866252206Sdavidcs	if (qls_sem_lock(ha, Q81_CTL_SEM_MASK_FLASH, Q81_CTL_SEM_SET_FLASH)) {
1867252206Sdavidcs		QL_DPRINT1((ha->pci_dev, "%s: semlock failed\n", __func__));
1868252206Sdavidcs		return(-1);
1869252206Sdavidcs	}
1870252206Sdavidcs
1871252206Sdavidcs	if ((ha->pci_func & 0x1) == 0)
1872252206Sdavidcs		faddr = Q81_F0_FLASH_OFFSET >> 2;
1873252206Sdavidcs	else
1874252206Sdavidcs		faddr = Q81_F1_FLASH_OFFSET >> 2;
1875252206Sdavidcs
1876252206Sdavidcs	qflash = (uint32_t *)&ha->flash;
1877252206Sdavidcs
1878252206Sdavidcs	for (i = 0; i < (sizeof(q81_flash_t) >> 2) ; i++) {
1879252206Sdavidcs
1880252206Sdavidcs		ret = qls_rd_flash32(ha, faddr, qflash);
1881252206Sdavidcs
1882252206Sdavidcs		if (ret)
1883252206Sdavidcs			goto qls_rd_flash_data_exit;
1884252206Sdavidcs
1885252206Sdavidcs		faddr++;
1886252206Sdavidcs		qflash++;
1887252206Sdavidcs	}
1888252206Sdavidcs
1889252206Sdavidcs	QL_DUMP_BUFFER8(ha, __func__, (&ha->flash), (sizeof (q81_flash_t)));
1890252206Sdavidcs
1891252206Sdavidcs	ret = qls_flash_validate(ha, Q81_FLASH_ID);
1892252206Sdavidcs
1893252206Sdavidcs	if (ret)
1894252206Sdavidcs		goto qls_rd_flash_data_exit;
1895252206Sdavidcs
1896252206Sdavidcs	bcopy(ha->flash.mac_addr0, ha->mac_addr, ETHER_ADDR_LEN);
1897252206Sdavidcs
1898252206Sdavidcs	QL_DPRINT1((ha->pci_dev, "%s: mac %02x:%02x:%02x:%02x:%02x:%02x\n",
1899252206Sdavidcs		__func__, ha->mac_addr[0],  ha->mac_addr[1], ha->mac_addr[2],
1900252206Sdavidcs		ha->mac_addr[3], ha->mac_addr[4],  ha->mac_addr[5]));
1901252206Sdavidcs
1902252206Sdavidcsqls_rd_flash_data_exit:
1903252206Sdavidcs
1904252206Sdavidcs	qls_sem_unlock(ha, Q81_CTL_SEM_MASK_FLASH);
1905252206Sdavidcs
1906252206Sdavidcs	return(ret);
1907252206Sdavidcs}
1908252206Sdavidcs
1909252206Sdavidcsstatic int
1910252206Sdavidcsqls_sem_lock(qla_host_t *ha, uint32_t mask, uint32_t value)
1911252206Sdavidcs{
1912252206Sdavidcs	uint32_t count = 30;
1913252206Sdavidcs	uint32_t data;
1914252206Sdavidcs
1915252206Sdavidcs	while (count--) {
1916252206Sdavidcs		WRITE_REG32(ha, Q81_CTL_SEMAPHORE, (mask|value));
1917252206Sdavidcs
1918252206Sdavidcs		data = READ_REG32(ha, Q81_CTL_SEMAPHORE);
1919252206Sdavidcs
1920252206Sdavidcs		if (data & value) {
1921252206Sdavidcs			return (0);
1922252206Sdavidcs		} else {
1923252206Sdavidcs			QLA_USEC_DELAY(100);
1924252206Sdavidcs		}
1925252206Sdavidcs	}
1926252206Sdavidcs	ha->qla_initiate_recovery = 1;
1927252206Sdavidcs	return (-1);
1928252206Sdavidcs}
1929252206Sdavidcs
1930252206Sdavidcsstatic void
1931252206Sdavidcsqls_sem_unlock(qla_host_t *ha, uint32_t mask)
1932252206Sdavidcs{
1933252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_SEMAPHORE, mask);
1934252206Sdavidcs}
1935252206Sdavidcs
1936252206Sdavidcsstatic int
1937252206Sdavidcsqls_wait_for_proc_addr_ready(qla_host_t *ha)
1938252206Sdavidcs{
1939252206Sdavidcs	uint32_t data32;
1940252206Sdavidcs	uint32_t count = 3;
1941252206Sdavidcs
1942252206Sdavidcs	while (count--) {
1943252206Sdavidcs
1944252206Sdavidcs		data32 = READ_REG32(ha, Q81_CTL_PROC_ADDR);
1945252206Sdavidcs
1946252206Sdavidcs		if (data32 & Q81_CTL_PROC_ADDR_ERR)
1947252206Sdavidcs			goto qls_wait_for_proc_addr_ready_exit;
1948252206Sdavidcs
1949252206Sdavidcs		if (data32 & Q81_CTL_PROC_ADDR_RDY)
1950252206Sdavidcs			return (0);
1951252206Sdavidcs
1952252206Sdavidcs		QLA_USEC_DELAY(100);
1953252206Sdavidcs	}
1954252206Sdavidcs
1955252206Sdavidcsqls_wait_for_proc_addr_ready_exit:
1956252206Sdavidcs	QL_DPRINT1((ha->pci_dev, "%s: failed\n", __func__));
1957252206Sdavidcs
1958252206Sdavidcs	ha->qla_initiate_recovery = 1;
1959252206Sdavidcs	return (-1);
1960252206Sdavidcs}
1961252206Sdavidcs
1962252206Sdavidcsstatic int
1963252206Sdavidcsqls_proc_addr_rd_reg(qla_host_t *ha, uint32_t addr_module, uint32_t reg,
1964252206Sdavidcs	uint32_t *data)
1965252206Sdavidcs{
1966252206Sdavidcs	int ret;
1967252206Sdavidcs	uint32_t value;
1968252206Sdavidcs
1969252206Sdavidcs	ret = qls_wait_for_proc_addr_ready(ha);
1970252206Sdavidcs
1971252206Sdavidcs	if (ret)
1972252206Sdavidcs		goto qls_proc_addr_rd_reg_exit;
1973252206Sdavidcs
1974252206Sdavidcs	value = addr_module | reg | Q81_CTL_PROC_ADDR_READ;
1975252206Sdavidcs
1976252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_PROC_ADDR, value);
1977252206Sdavidcs
1978252206Sdavidcs	ret = qls_wait_for_proc_addr_ready(ha);
1979252206Sdavidcs
1980252206Sdavidcs	if (ret)
1981252206Sdavidcs		goto qls_proc_addr_rd_reg_exit;
1982252206Sdavidcs
1983252206Sdavidcs	*data = READ_REG32(ha, Q81_CTL_PROC_DATA);
1984252206Sdavidcs
1985252206Sdavidcsqls_proc_addr_rd_reg_exit:
1986252206Sdavidcs	return (ret);
1987252206Sdavidcs}
1988252206Sdavidcs
1989252206Sdavidcsstatic int
1990252206Sdavidcsqls_proc_addr_wr_reg(qla_host_t *ha, uint32_t addr_module, uint32_t reg,
1991252206Sdavidcs	uint32_t data)
1992252206Sdavidcs{
1993252206Sdavidcs	int ret;
1994252206Sdavidcs	uint32_t value;
1995252206Sdavidcs
1996252206Sdavidcs	ret = qls_wait_for_proc_addr_ready(ha);
1997252206Sdavidcs
1998252206Sdavidcs	if (ret)
1999252206Sdavidcs		goto qls_proc_addr_wr_reg_exit;
2000252206Sdavidcs
2001252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_PROC_DATA, data);
2002252206Sdavidcs
2003252206Sdavidcs	value = addr_module | reg;
2004252206Sdavidcs
2005252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_PROC_ADDR, value);
2006252206Sdavidcs
2007252206Sdavidcs	ret = qls_wait_for_proc_addr_ready(ha);
2008252206Sdavidcs
2009252206Sdavidcsqls_proc_addr_wr_reg_exit:
2010252206Sdavidcs	return (ret);
2011252206Sdavidcs}
2012252206Sdavidcs
2013252206Sdavidcsstatic int
2014252206Sdavidcsqls_hw_nic_reset(qla_host_t *ha)
2015252206Sdavidcs{
2016252206Sdavidcs	int		count;
2017252206Sdavidcs	uint32_t	data;
2018252206Sdavidcs	device_t	dev = ha->pci_dev;
2019252206Sdavidcs
2020252206Sdavidcs	ha->hw_init = 0;
2021252206Sdavidcs
2022252206Sdavidcs	data = (Q81_CTL_RESET_FUNC << Q81_CTL_RESET_MASK_SHIFT) |
2023252206Sdavidcs			Q81_CTL_RESET_FUNC;
2024252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_RESET, data);
2025252206Sdavidcs
2026252206Sdavidcs	count = 10;
2027252206Sdavidcs	while (count--) {
2028252206Sdavidcs		data = READ_REG32(ha, Q81_CTL_RESET);
2029252206Sdavidcs		if ((data & Q81_CTL_RESET_FUNC) == 0)
2030252206Sdavidcs			break;
2031252206Sdavidcs		QLA_USEC_DELAY(10);
2032252206Sdavidcs	}
2033252206Sdavidcs	if (count == 0) {
2034252206Sdavidcs		device_printf(dev, "%s: Bit 15 not cleared after Reset\n",
2035252206Sdavidcs			__func__);
2036252206Sdavidcs		return (-1);
2037252206Sdavidcs	}
2038252206Sdavidcs	return (0);
2039252206Sdavidcs}
2040252206Sdavidcs
2041252206Sdavidcsstatic int
2042252206Sdavidcsqls_hw_reset(qla_host_t *ha)
2043252206Sdavidcs{
2044252206Sdavidcs	device_t	dev = ha->pci_dev;
2045252206Sdavidcs	int		ret;
2046252206Sdavidcs	int		count;
2047252206Sdavidcs	uint32_t	data;
2048252206Sdavidcs
2049252206Sdavidcs	QL_DPRINT2((ha->pci_dev, "%s:enter[%d]\n", __func__, ha->hw_init));
2050252206Sdavidcs
2051252206Sdavidcs	if (ha->hw_init == 0) {
2052252206Sdavidcs		ret = qls_hw_nic_reset(ha);
2053252206Sdavidcs		goto qls_hw_reset_exit;
2054252206Sdavidcs	}
2055252206Sdavidcs
2056252206Sdavidcs	ret = qls_clear_routing_table(ha);
2057252206Sdavidcs	if (ret)
2058252206Sdavidcs		goto qls_hw_reset_exit;
2059252206Sdavidcs
2060252206Sdavidcs	ret = qls_mbx_set_mgmt_ctrl(ha, Q81_MBX_SET_MGMT_CTL_STOP);
2061252206Sdavidcs	if (ret)
2062252206Sdavidcs		goto qls_hw_reset_exit;
2063252206Sdavidcs
2064252206Sdavidcs	/*
2065252206Sdavidcs	 * Wait for FIFO to empty
2066252206Sdavidcs	 */
2067252206Sdavidcs	count = 5;
2068252206Sdavidcs	while (count--) {
2069252206Sdavidcs		data = READ_REG32(ha, Q81_CTL_STATUS);
2070252206Sdavidcs		if (data & Q81_CTL_STATUS_NFE)
2071252206Sdavidcs			break;
2072252206Sdavidcs		qls_mdelay(__func__, 100);
2073252206Sdavidcs	}
2074252206Sdavidcs	if (count == 0) {
2075252206Sdavidcs		device_printf(dev, "%s: NFE bit not set\n", __func__);
2076252206Sdavidcs		goto qls_hw_reset_exit;
2077252206Sdavidcs	}
2078252206Sdavidcs
2079252206Sdavidcs	count = 5;
2080252206Sdavidcs	while (count--) {
2081252206Sdavidcs		(void)qls_mbx_get_mgmt_ctrl(ha, &data);
2082252206Sdavidcs
2083252206Sdavidcs		if ((data & Q81_MBX_GET_MGMT_CTL_FIFO_EMPTY) &&
2084252206Sdavidcs			(data & Q81_MBX_GET_MGMT_CTL_SET_MGMT))
2085252206Sdavidcs			break;
2086252206Sdavidcs		qls_mdelay(__func__, 100);
2087252206Sdavidcs	}
2088252206Sdavidcs	if (count == 0)
2089252206Sdavidcs		goto qls_hw_reset_exit;
2090252206Sdavidcs
2091252206Sdavidcs	/*
2092252206Sdavidcs	 * Reset the NIC function
2093252206Sdavidcs	 */
2094252206Sdavidcs	ret = qls_hw_nic_reset(ha);
2095252206Sdavidcs	if (ret)
2096252206Sdavidcs		goto qls_hw_reset_exit;
2097252206Sdavidcs
2098252206Sdavidcs	ret = qls_mbx_set_mgmt_ctrl(ha, Q81_MBX_SET_MGMT_CTL_RESUME);
2099252206Sdavidcs
2100252206Sdavidcsqls_hw_reset_exit:
2101252206Sdavidcs	if (ret)
2102252206Sdavidcs		device_printf(dev, "%s: failed\n", __func__);
2103252206Sdavidcs
2104252206Sdavidcs	return (ret);
2105252206Sdavidcs}
2106252206Sdavidcs
2107252206Sdavidcs/*
2108252206Sdavidcs * MPI Related Functions
2109252206Sdavidcs */
2110252206Sdavidcsint
2111252206Sdavidcsqls_mpi_risc_rd_reg(qla_host_t *ha, uint32_t reg, uint32_t *data)
2112252206Sdavidcs{
2113252206Sdavidcs	int ret;
2114252206Sdavidcs
2115252206Sdavidcs	ret = qls_proc_addr_rd_reg(ha, Q81_CTL_PROC_ADDR_MPI_RISC,
2116252206Sdavidcs			reg, data);
2117252206Sdavidcs	return (ret);
2118252206Sdavidcs}
2119252206Sdavidcs
2120252206Sdavidcsint
2121252206Sdavidcsqls_mpi_risc_wr_reg(qla_host_t *ha, uint32_t reg, uint32_t data)
2122252206Sdavidcs{
2123252206Sdavidcs	int ret;
2124252206Sdavidcs
2125252206Sdavidcs	ret = qls_proc_addr_wr_reg(ha, Q81_CTL_PROC_ADDR_MPI_RISC,
2126252206Sdavidcs			reg, data);
2127252206Sdavidcs	return (ret);
2128252206Sdavidcs}
2129252206Sdavidcs
2130252206Sdavidcsint
2131252206Sdavidcsqls_mbx_rd_reg(qla_host_t *ha, uint32_t reg, uint32_t *data)
2132252206Sdavidcs{
2133252206Sdavidcs	int ret;
2134252206Sdavidcs
2135252206Sdavidcs	if ((ha->pci_func & 0x1) == 0)
2136252206Sdavidcs		reg += Q81_FUNC0_MBX_OUT_REG0;
2137252206Sdavidcs	else
2138252206Sdavidcs		reg += Q81_FUNC1_MBX_OUT_REG0;
2139252206Sdavidcs
2140252206Sdavidcs	ret = qls_mpi_risc_rd_reg(ha, reg, data);
2141252206Sdavidcs
2142252206Sdavidcs	return (ret);
2143252206Sdavidcs}
2144252206Sdavidcs
2145252206Sdavidcsint
2146252206Sdavidcsqls_mbx_wr_reg(qla_host_t *ha, uint32_t reg, uint32_t data)
2147252206Sdavidcs{
2148252206Sdavidcs	int ret;
2149252206Sdavidcs
2150252206Sdavidcs	if ((ha->pci_func & 0x1) == 0)
2151252206Sdavidcs		reg += Q81_FUNC0_MBX_IN_REG0;
2152252206Sdavidcs	else
2153252206Sdavidcs		reg += Q81_FUNC1_MBX_IN_REG0;
2154252206Sdavidcs
2155252206Sdavidcs	ret = qls_mpi_risc_wr_reg(ha, reg, data);
2156252206Sdavidcs
2157252206Sdavidcs	return (ret);
2158252206Sdavidcs}
2159252206Sdavidcs
2160252206Sdavidcs
2161252206Sdavidcsstatic int
2162252206Sdavidcsqls_mbx_cmd(qla_host_t *ha, uint32_t *in_mbx, uint32_t i_count,
2163252206Sdavidcs	uint32_t *out_mbx, uint32_t o_count)
2164252206Sdavidcs{
2165252206Sdavidcs	int i, ret = -1;
2166252206Sdavidcs	uint32_t data32, mbx_cmd = 0;
2167252206Sdavidcs	uint32_t count = 50;
2168252206Sdavidcs
2169252206Sdavidcs	QL_DPRINT2((ha->pci_dev, "%s: enter[0x%08x 0x%08x 0x%08x]\n",
2170252206Sdavidcs		__func__, *in_mbx, *(in_mbx + 1), *(in_mbx + 2)));
2171252206Sdavidcs
2172252206Sdavidcs	data32 = READ_REG32(ha, Q81_CTL_HOST_CMD_STATUS);
2173252206Sdavidcs
2174252206Sdavidcs	if (data32 & Q81_CTL_HCS_HTR_INTR) {
2175252206Sdavidcs		device_printf(ha->pci_dev, "%s: cmd_status[0x%08x]\n",
2176252206Sdavidcs			__func__, data32);
2177252206Sdavidcs		goto qls_mbx_cmd_exit;
2178252206Sdavidcs	}
2179252206Sdavidcs
2180252206Sdavidcs	if (qls_sem_lock(ha, Q81_CTL_SEM_MASK_PROC_ADDR_NIC_RCV,
2181252206Sdavidcs		Q81_CTL_SEM_SET_PROC_ADDR_NIC_RCV)) {
2182252206Sdavidcs		device_printf(ha->pci_dev, "%s: semlock failed\n", __func__);
2183252206Sdavidcs		goto qls_mbx_cmd_exit;
2184252206Sdavidcs	}
2185252206Sdavidcs
2186252206Sdavidcs	ha->mbx_done = 0;
2187252206Sdavidcs
2188252206Sdavidcs	mbx_cmd = *in_mbx;
2189252206Sdavidcs
2190252206Sdavidcs	for (i = 0; i < i_count; i++) {
2191252206Sdavidcs
2192252206Sdavidcs		ret = qls_mbx_wr_reg(ha, i, *in_mbx);
2193252206Sdavidcs
2194252206Sdavidcs		if (ret) {
2195252206Sdavidcs			device_printf(ha->pci_dev,
2196252206Sdavidcs				"%s: mbx_wr[%d, 0x%08x] failed\n", __func__,
2197252206Sdavidcs				i, *in_mbx);
2198252206Sdavidcs			qls_sem_unlock(ha, Q81_CTL_SEM_MASK_PROC_ADDR_NIC_RCV);
2199252206Sdavidcs			goto qls_mbx_cmd_exit;
2200252206Sdavidcs		}
2201252206Sdavidcs
2202252206Sdavidcs		in_mbx++;
2203252206Sdavidcs	}
2204252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_HOST_CMD_STATUS, Q81_CTL_HCS_CMD_SET_HTR_INTR);
2205252206Sdavidcs
2206252206Sdavidcs	qls_sem_unlock(ha, Q81_CTL_SEM_MASK_PROC_ADDR_NIC_RCV);
2207252206Sdavidcs
2208252206Sdavidcs	ret = -1;
2209252206Sdavidcs	ha->mbx_done = 0;
2210252206Sdavidcs
2211252206Sdavidcs	while (count--) {
2212252206Sdavidcs
2213252206Sdavidcs		if (ha->flags.intr_enable == 0) {
2214252206Sdavidcs			data32 = READ_REG32(ha, Q81_CTL_STATUS);
2215252206Sdavidcs
2216252206Sdavidcs			if (!(data32 & Q81_CTL_STATUS_PI)) {
2217252206Sdavidcs				qls_mdelay(__func__, 100);
2218252206Sdavidcs				continue;
2219252206Sdavidcs			}
2220252206Sdavidcs
2221252206Sdavidcs			ret = qls_mbx_rd_reg(ha, 0, &data32);
2222252206Sdavidcs
2223252206Sdavidcs			if (ret == 0 ) {
2224252206Sdavidcs				if ((data32 & 0xF000) == 0x4000) {
2225252206Sdavidcs
2226252206Sdavidcs					out_mbx[0] = data32;
2227252206Sdavidcs
2228252206Sdavidcs					for (i = 1; i < o_count; i++) {
2229252206Sdavidcs						ret = qls_mbx_rd_reg(ha, i,
2230252206Sdavidcs								&data32);
2231252206Sdavidcs						if (ret) {
2232252206Sdavidcs							device_printf(
2233252206Sdavidcs								ha->pci_dev,
2234252206Sdavidcs								"%s: mbx_rd[%d]"
2235252206Sdavidcs								" failed\n",
2236252206Sdavidcs								__func__, i);
2237252206Sdavidcs							break;
2238252206Sdavidcs						}
2239252206Sdavidcs						out_mbx[i] = data32;
2240252206Sdavidcs					}
2241252206Sdavidcs					break;
2242252206Sdavidcs				} else if ((data32 & 0xF000) == 0x8000) {
2243252206Sdavidcs					count = 50;
2244252206Sdavidcs					WRITE_REG32(ha,\
2245252206Sdavidcs						Q81_CTL_HOST_CMD_STATUS,\
2246252206Sdavidcs						Q81_CTL_HCS_CMD_CLR_RTH_INTR);
2247252206Sdavidcs				}
2248252206Sdavidcs			}
2249252206Sdavidcs		} else {
2250252206Sdavidcs			if (ha->mbx_done) {
2251252206Sdavidcs				for (i = 1; i < o_count; i++) {
2252252206Sdavidcs					out_mbx[i] = ha->mbox[i];
2253252206Sdavidcs				}
2254252206Sdavidcs				ret = 0;
2255252206Sdavidcs				break;
2256252206Sdavidcs			}
2257252206Sdavidcs		}
2258252206Sdavidcs		qls_mdelay(__func__, 1000);
2259252206Sdavidcs	}
2260252206Sdavidcs
2261252206Sdavidcsqls_mbx_cmd_exit:
2262252206Sdavidcs
2263252206Sdavidcs	if (ha->flags.intr_enable == 0) {
2264252206Sdavidcs		WRITE_REG32(ha, Q81_CTL_HOST_CMD_STATUS,\
2265252206Sdavidcs			Q81_CTL_HCS_CMD_CLR_RTH_INTR);
2266252206Sdavidcs	}
2267252206Sdavidcs
2268252206Sdavidcs	if (ret) {
2269252206Sdavidcs		ha->qla_initiate_recovery = 1;
2270252206Sdavidcs	}
2271252206Sdavidcs
2272252206Sdavidcs	QL_DPRINT2((ha->pci_dev, "%s: exit[%d]\n", __func__, ret));
2273252206Sdavidcs	return (ret);
2274252206Sdavidcs}
2275252206Sdavidcs
2276252206Sdavidcsstatic int
2277252206Sdavidcsqls_mbx_set_mgmt_ctrl(qla_host_t *ha, uint32_t t_ctrl)
2278252206Sdavidcs{
2279252206Sdavidcs	uint32_t *mbox;
2280252206Sdavidcs	device_t dev = ha->pci_dev;
2281252206Sdavidcs
2282252206Sdavidcs	mbox = ha->mbox;
2283252206Sdavidcs	bzero(mbox, (sizeof (uint32_t) * Q81_NUM_MBX_REGISTERS));
2284252206Sdavidcs
2285252206Sdavidcs	mbox[0] = Q81_MBX_SET_MGMT_CTL;
2286252206Sdavidcs	mbox[1] = t_ctrl;
2287252206Sdavidcs
2288252206Sdavidcs	if (qls_mbx_cmd(ha, mbox, 2, mbox, 1)) {
2289252206Sdavidcs		device_printf(dev, "%s failed\n", __func__);
2290252206Sdavidcs		return (-1);
2291252206Sdavidcs	}
2292252206Sdavidcs
2293252206Sdavidcs	if ((mbox[0] == Q81_MBX_CMD_COMPLETE) ||
2294252206Sdavidcs		((t_ctrl == Q81_MBX_SET_MGMT_CTL_STOP) &&
2295252206Sdavidcs			(mbox[0] == Q81_MBX_CMD_ERROR))){
2296252206Sdavidcs		return (0);
2297252206Sdavidcs	}
2298252206Sdavidcs	device_printf(dev, "%s failed [0x%08x]\n", __func__, mbox[0]);
2299252206Sdavidcs	return (-1);
2300252206Sdavidcs
2301252206Sdavidcs}
2302252206Sdavidcs
2303252206Sdavidcsstatic int
2304252206Sdavidcsqls_mbx_get_mgmt_ctrl(qla_host_t *ha, uint32_t *t_status)
2305252206Sdavidcs{
2306252206Sdavidcs	uint32_t *mbox;
2307252206Sdavidcs	device_t dev = ha->pci_dev;
2308252206Sdavidcs
2309252206Sdavidcs	*t_status = 0;
2310252206Sdavidcs
2311252206Sdavidcs	mbox = ha->mbox;
2312252206Sdavidcs	bzero(mbox, (sizeof (uint32_t) * Q81_NUM_MBX_REGISTERS));
2313252206Sdavidcs
2314252206Sdavidcs	mbox[0] = Q81_MBX_GET_MGMT_CTL;
2315252206Sdavidcs
2316252206Sdavidcs	if (qls_mbx_cmd(ha, mbox, 1, mbox, 2)) {
2317252206Sdavidcs		device_printf(dev, "%s failed\n", __func__);
2318252206Sdavidcs		return (-1);
2319252206Sdavidcs	}
2320252206Sdavidcs
2321252206Sdavidcs	*t_status = mbox[1];
2322252206Sdavidcs
2323252206Sdavidcs	return (0);
2324252206Sdavidcs}
2325252206Sdavidcs
2326252206Sdavidcsstatic void
2327252206Sdavidcsqls_mbx_get_link_status(qla_host_t *ha)
2328252206Sdavidcs{
2329252206Sdavidcs	uint32_t *mbox;
2330252206Sdavidcs	device_t dev = ha->pci_dev;
2331252206Sdavidcs
2332252206Sdavidcs	mbox = ha->mbox;
2333252206Sdavidcs	bzero(mbox, (sizeof (uint32_t) * Q81_NUM_MBX_REGISTERS));
2334252206Sdavidcs
2335252206Sdavidcs	mbox[0] = Q81_MBX_GET_LNK_STATUS;
2336252206Sdavidcs
2337252206Sdavidcs	if (qls_mbx_cmd(ha, mbox, 1, mbox, 6)) {
2338252206Sdavidcs		device_printf(dev, "%s failed\n", __func__);
2339252206Sdavidcs		return;
2340252206Sdavidcs	}
2341252206Sdavidcs
2342252206Sdavidcs	ha->link_status			= mbox[1];
2343252206Sdavidcs	ha->link_down_info		= mbox[2];
2344252206Sdavidcs	ha->link_hw_info		= mbox[3];
2345252206Sdavidcs	ha->link_dcbx_counters		= mbox[4];
2346252206Sdavidcs	ha->link_change_counters	= mbox[5];
2347252206Sdavidcs
2348252206Sdavidcs	device_printf(dev, "%s 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
2349252206Sdavidcs		__func__, mbox[0],mbox[1],mbox[2],mbox[3],mbox[4],mbox[5]);
2350252206Sdavidcs
2351252206Sdavidcs	return;
2352252206Sdavidcs}
2353252206Sdavidcs
2354252206Sdavidcsstatic void
2355252206Sdavidcsqls_mbx_about_fw(qla_host_t *ha)
2356252206Sdavidcs{
2357252206Sdavidcs	uint32_t *mbox;
2358252206Sdavidcs	device_t dev = ha->pci_dev;
2359252206Sdavidcs
2360252206Sdavidcs	mbox = ha->mbox;
2361252206Sdavidcs	bzero(mbox, (sizeof (uint32_t) * Q81_NUM_MBX_REGISTERS));
2362252206Sdavidcs
2363252206Sdavidcs	mbox[0] = Q81_MBX_ABOUT_FW;
2364252206Sdavidcs
2365252206Sdavidcs	if (qls_mbx_cmd(ha, mbox, 1, mbox, 6)) {
2366252206Sdavidcs		device_printf(dev, "%s failed\n", __func__);
2367252206Sdavidcs		return;
2368252206Sdavidcs	}
2369252206Sdavidcs
2370252206Sdavidcs	device_printf(dev, "%s 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
2371252206Sdavidcs		__func__, mbox[0],mbox[1],mbox[2],mbox[3],mbox[4],mbox[5]);
2372252206Sdavidcs}
2373252206Sdavidcs
2374252206Sdavidcsint
2375252206Sdavidcsqls_mbx_dump_risc_ram(qla_host_t *ha, void *buf, uint32_t r_addr,
2376252206Sdavidcs	uint32_t r_size)
2377252206Sdavidcs{
2378252206Sdavidcs	bus_addr_t b_paddr;
2379252206Sdavidcs	uint32_t *mbox;
2380252206Sdavidcs	device_t dev = ha->pci_dev;
2381252206Sdavidcs
2382252206Sdavidcs	mbox = ha->mbox;
2383252206Sdavidcs	bzero(mbox, (sizeof (uint32_t) * Q81_NUM_MBX_REGISTERS));
2384252206Sdavidcs
2385252206Sdavidcs	bzero(ha->mpi_dma.dma_b,(r_size << 2));
2386252206Sdavidcs	b_paddr = ha->mpi_dma.dma_addr;
2387252206Sdavidcs
2388252206Sdavidcs	mbox[0] = Q81_MBX_DUMP_RISC_RAM;
2389252206Sdavidcs	mbox[1] = r_addr & 0xFFFF;
2390252206Sdavidcs	mbox[2] = ((uint32_t)(b_paddr >> 16)) & 0xFFFF;
2391252206Sdavidcs	mbox[3] = ((uint32_t)b_paddr) & 0xFFFF;
2392252206Sdavidcs	mbox[4] = (r_size >> 16) & 0xFFFF;
2393252206Sdavidcs	mbox[5] = r_size & 0xFFFF;
2394252206Sdavidcs	mbox[6] = ((uint32_t)(b_paddr >> 48)) & 0xFFFF;
2395252206Sdavidcs	mbox[7] = ((uint32_t)(b_paddr >> 32)) & 0xFFFF;
2396252206Sdavidcs	mbox[8] = (r_addr >> 16) & 0xFFFF;
2397252206Sdavidcs
2398252206Sdavidcs	bus_dmamap_sync(ha->mpi_dma.dma_tag, ha->mpi_dma.dma_map,
2399252206Sdavidcs		BUS_DMASYNC_PREREAD);
2400252206Sdavidcs
2401252206Sdavidcs	if (qls_mbx_cmd(ha, mbox, 9, mbox, 1)) {
2402252206Sdavidcs		device_printf(dev, "%s failed\n", __func__);
2403252206Sdavidcs		return (-1);
2404252206Sdavidcs	}
2405252206Sdavidcs        if (mbox[0] != 0x4000) {
2406252206Sdavidcs                device_printf(ha->pci_dev, "%s: failed!\n", __func__);
2407252206Sdavidcs		return (-1);
2408252206Sdavidcs        } else {
2409252206Sdavidcs                bus_dmamap_sync(ha->mpi_dma.dma_tag, ha->mpi_dma.dma_map,
2410252206Sdavidcs                        BUS_DMASYNC_POSTREAD);
2411252206Sdavidcs                bcopy(ha->mpi_dma.dma_b, buf, (r_size << 2));
2412252206Sdavidcs        }
2413252206Sdavidcs
2414252206Sdavidcs	return (0);
2415252206Sdavidcs}
2416252206Sdavidcs
2417252206Sdavidcsint
2418252206Sdavidcsqls_mpi_reset(qla_host_t *ha)
2419252206Sdavidcs{
2420252206Sdavidcs	int		count;
2421252206Sdavidcs	uint32_t	data;
2422252206Sdavidcs	device_t	dev = ha->pci_dev;
2423252206Sdavidcs
2424252206Sdavidcs	WRITE_REG32(ha, Q81_CTL_HOST_CMD_STATUS,\
2425252206Sdavidcs		Q81_CTL_HCS_CMD_SET_RISC_RESET);
2426252206Sdavidcs
2427252206Sdavidcs	count = 10;
2428252206Sdavidcs	while (count--) {
2429252206Sdavidcs		data = READ_REG32(ha, Q81_CTL_HOST_CMD_STATUS);
2430252206Sdavidcs		if (data & Q81_CTL_HCS_RISC_RESET) {
2431252206Sdavidcs			WRITE_REG32(ha, Q81_CTL_HOST_CMD_STATUS,\
2432252206Sdavidcs				Q81_CTL_HCS_CMD_CLR_RISC_RESET);
2433252206Sdavidcs			break;
2434252206Sdavidcs		}
2435252206Sdavidcs		qls_mdelay(__func__, 10);
2436252206Sdavidcs	}
2437252206Sdavidcs	if (count == 0) {
2438252206Sdavidcs		device_printf(dev, "%s: failed\n", __func__);
2439252206Sdavidcs		return (-1);
2440252206Sdavidcs	}
2441252206Sdavidcs	return (0);
2442252206Sdavidcs}
2443252206Sdavidcs
2444