xref: /freebsd/sys/dev/qlxge/qls_isr.c (revision 718cf2ccb9956613756ab15d7a0e28f2c8e91cab)
1*718cf2ccSPedro F. Giffuni /*-
2*718cf2ccSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*718cf2ccSPedro F. Giffuni  *
4*718cf2ccSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
5*718cf2ccSPedro F. Giffuni  *
6711bcba0SDavid C Somayajulu  * Copyright (c) 2013-2014 Qlogic Corporation
7711bcba0SDavid C Somayajulu  * All rights reserved.
8711bcba0SDavid C Somayajulu  *
9711bcba0SDavid C Somayajulu  *  Redistribution and use in source and binary forms, with or without
10711bcba0SDavid C Somayajulu  *  modification, are permitted provided that the following conditions
11711bcba0SDavid C Somayajulu  *  are met:
12711bcba0SDavid C Somayajulu  *
13711bcba0SDavid C Somayajulu  *  1. Redistributions of source code must retain the above copyright
14711bcba0SDavid C Somayajulu  *     notice, this list of conditions and the following disclaimer.
15711bcba0SDavid C Somayajulu  *  2. Redistributions in binary form must reproduce the above copyright
16711bcba0SDavid C Somayajulu  *     notice, this list of conditions and the following disclaimer in the
17711bcba0SDavid C Somayajulu  *     documentation and/or other materials provided with the distribution.
18711bcba0SDavid C Somayajulu  *
19711bcba0SDavid C Somayajulu  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20711bcba0SDavid C Somayajulu  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21711bcba0SDavid C Somayajulu  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22711bcba0SDavid C Somayajulu  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23711bcba0SDavid C Somayajulu  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24711bcba0SDavid C Somayajulu  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25711bcba0SDavid C Somayajulu  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26711bcba0SDavid C Somayajulu  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27711bcba0SDavid C Somayajulu  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28711bcba0SDavid C Somayajulu  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29711bcba0SDavid C Somayajulu  *  POSSIBILITY OF SUCH DAMAGE.
30711bcba0SDavid C Somayajulu  */
31711bcba0SDavid C Somayajulu 
32711bcba0SDavid C Somayajulu /*
33711bcba0SDavid C Somayajulu  * File: qls_isr.c
34711bcba0SDavid C Somayajulu  * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656.
35711bcba0SDavid C Somayajulu  */
36711bcba0SDavid C Somayajulu #include <sys/cdefs.h>
37711bcba0SDavid C Somayajulu __FBSDID("$FreeBSD$");
38711bcba0SDavid C Somayajulu 
39711bcba0SDavid C Somayajulu 
40711bcba0SDavid C Somayajulu 
41711bcba0SDavid C Somayajulu #include "qls_os.h"
42711bcba0SDavid C Somayajulu #include "qls_hw.h"
43711bcba0SDavid C Somayajulu #include "qls_def.h"
44711bcba0SDavid C Somayajulu #include "qls_inline.h"
45711bcba0SDavid C Somayajulu #include "qls_ver.h"
46711bcba0SDavid C Somayajulu #include "qls_glbl.h"
47711bcba0SDavid C Somayajulu #include "qls_dbg.h"
48711bcba0SDavid C Somayajulu 
49711bcba0SDavid C Somayajulu 
50711bcba0SDavid C Somayajulu static void
51711bcba0SDavid C Somayajulu qls_tx_comp(qla_host_t *ha, uint32_t txr_idx, q81_tx_mac_comp_t *tx_comp)
52711bcba0SDavid C Somayajulu {
53711bcba0SDavid C Somayajulu 	qla_tx_buf_t *txb;
54711bcba0SDavid C Somayajulu 	uint32_t tx_idx = tx_comp->tid_lo;
55711bcba0SDavid C Somayajulu 
56711bcba0SDavid C Somayajulu 	if (tx_idx >= NUM_TX_DESCRIPTORS) {
57711bcba0SDavid C Somayajulu 		ha->qla_initiate_recovery = 1;
58711bcba0SDavid C Somayajulu 		return;
59711bcba0SDavid C Somayajulu 	}
60711bcba0SDavid C Somayajulu 
61711bcba0SDavid C Somayajulu 	txb = &ha->tx_ring[txr_idx].tx_buf[tx_idx];
62711bcba0SDavid C Somayajulu 
63711bcba0SDavid C Somayajulu 	if (txb->m_head) {
64c8dfaf38SGleb Smirnoff 		if_inc_counter(ha->ifp, IFCOUNTER_OPACKETS, 1);
65711bcba0SDavid C Somayajulu 		bus_dmamap_sync(ha->tx_tag, txb->map,
66711bcba0SDavid C Somayajulu 		        BUS_DMASYNC_POSTWRITE);
67711bcba0SDavid C Somayajulu 		bus_dmamap_unload(ha->tx_tag, txb->map);
68711bcba0SDavid C Somayajulu 		m_freem(txb->m_head);
69711bcba0SDavid C Somayajulu 
70711bcba0SDavid C Somayajulu 		txb->m_head = NULL;
71711bcba0SDavid C Somayajulu 	}
72711bcba0SDavid C Somayajulu 
73711bcba0SDavid C Somayajulu         ha->tx_ring[txr_idx].txr_done++;
74711bcba0SDavid C Somayajulu 
75711bcba0SDavid C Somayajulu 	if (ha->tx_ring[txr_idx].txr_done == NUM_TX_DESCRIPTORS)
76711bcba0SDavid C Somayajulu 		ha->tx_ring[txr_idx].txr_done = 0;
77711bcba0SDavid C Somayajulu }
78711bcba0SDavid C Somayajulu 
79711bcba0SDavid C Somayajulu static void
80711bcba0SDavid C Somayajulu qls_replenish_rx(qla_host_t *ha, uint32_t r_idx)
81711bcba0SDavid C Somayajulu {
82711bcba0SDavid C Somayajulu         qla_rx_buf_t			*rxb;
83711bcba0SDavid C Somayajulu 	qla_rx_ring_t			*rxr;
84711bcba0SDavid C Somayajulu         int				count;
85711bcba0SDavid C Somayajulu 	volatile q81_bq_addr_e_t	*sbq_e;
86711bcba0SDavid C Somayajulu 
87711bcba0SDavid C Somayajulu 	rxr = &ha->rx_ring[r_idx];
88711bcba0SDavid C Somayajulu 
89711bcba0SDavid C Somayajulu 	count = rxr->rx_free;
90711bcba0SDavid C Somayajulu 	sbq_e = rxr->sbq_vaddr;
91711bcba0SDavid C Somayajulu 
92711bcba0SDavid C Somayajulu         while (count--) {
93711bcba0SDavid C Somayajulu 
94711bcba0SDavid C Somayajulu 		rxb = &rxr->rx_buf[rxr->sbq_next];
95711bcba0SDavid C Somayajulu 
96711bcba0SDavid C Somayajulu 		if (rxb->m_head == NULL) {
97711bcba0SDavid C Somayajulu                 	if (qls_get_mbuf(ha, rxb, NULL) != 0) {
98711bcba0SDavid C Somayajulu                         	device_printf(ha->pci_dev,
99711bcba0SDavid C Somayajulu 					"%s: qls_get_mbuf [0,%d,%d] failed\n",
100711bcba0SDavid C Somayajulu 					__func__, rxr->sbq_next, r_idx);
101711bcba0SDavid C Somayajulu 				rxb->m_head = NULL;
102711bcba0SDavid C Somayajulu 				break;
103711bcba0SDavid C Somayajulu 			}
104711bcba0SDavid C Somayajulu 		}
105711bcba0SDavid C Somayajulu 
106711bcba0SDavid C Somayajulu 		if (rxb->m_head != NULL) {
107711bcba0SDavid C Somayajulu 			sbq_e[rxr->sbq_next].addr_lo = (uint32_t)rxb->paddr;
108711bcba0SDavid C Somayajulu 			sbq_e[rxr->sbq_next].addr_hi =
109711bcba0SDavid C Somayajulu 				(uint32_t)(rxb->paddr >> 32);
110711bcba0SDavid C Somayajulu 
111711bcba0SDavid C Somayajulu                         rxr->sbq_next++;
112711bcba0SDavid C Somayajulu                         if (rxr->sbq_next == NUM_RX_DESCRIPTORS)
113711bcba0SDavid C Somayajulu                                 rxr->sbq_next = 0;
114711bcba0SDavid C Somayajulu 
115711bcba0SDavid C Somayajulu 			rxr->sbq_free++;
116711bcba0SDavid C Somayajulu                 	rxr->rx_free--;
117711bcba0SDavid C Somayajulu 		}
118711bcba0SDavid C Somayajulu 
119711bcba0SDavid C Somayajulu                 if (rxr->sbq_free == 16) {
120711bcba0SDavid C Somayajulu 
121711bcba0SDavid C Somayajulu 			rxr->sbq_in += 16;
122711bcba0SDavid C Somayajulu 			rxr->sbq_in = rxr->sbq_in & (NUM_RX_DESCRIPTORS - 1);
123711bcba0SDavid C Somayajulu 			rxr->sbq_free = 0;
124711bcba0SDavid C Somayajulu 
125711bcba0SDavid C Somayajulu 			Q81_WR_SBQ_PROD_IDX(r_idx, (rxr->sbq_in));
126711bcba0SDavid C Somayajulu                 }
127711bcba0SDavid C Somayajulu         }
128711bcba0SDavid C Somayajulu }
129711bcba0SDavid C Somayajulu 
130711bcba0SDavid C Somayajulu static int
131711bcba0SDavid C Somayajulu qls_rx_comp(qla_host_t *ha, uint32_t rxr_idx, uint32_t cq_idx, q81_rx_t *cq_e)
132711bcba0SDavid C Somayajulu {
133711bcba0SDavid C Somayajulu 	qla_rx_buf_t	*rxb;
134711bcba0SDavid C Somayajulu 	qla_rx_ring_t	*rxr;
135711bcba0SDavid C Somayajulu 	device_t	dev = ha->pci_dev;
136711bcba0SDavid C Somayajulu 	struct mbuf     *mp = NULL;
137711bcba0SDavid C Somayajulu 	struct ifnet	*ifp = ha->ifp;
138711bcba0SDavid C Somayajulu 	struct lro_ctrl	*lro;
139711bcba0SDavid C Somayajulu 	struct ether_vlan_header *eh;
140711bcba0SDavid C Somayajulu 
141711bcba0SDavid C Somayajulu 	rxr = &ha->rx_ring[rxr_idx];
142711bcba0SDavid C Somayajulu 
143711bcba0SDavid C Somayajulu 	lro = &rxr->lro;
144711bcba0SDavid C Somayajulu 
145711bcba0SDavid C Somayajulu 	rxb = &rxr->rx_buf[rxr->rx_next];
146711bcba0SDavid C Somayajulu 
147711bcba0SDavid C Somayajulu 	if (!(cq_e->flags1 & Q81_RX_FLAGS1_DS)) {
148711bcba0SDavid C Somayajulu 		device_printf(dev, "%s: DS bit not set \n", __func__);
149711bcba0SDavid C Somayajulu 		return -1;
150711bcba0SDavid C Somayajulu 	}
151711bcba0SDavid C Somayajulu 	if (rxb->paddr != cq_e->b_paddr) {
152711bcba0SDavid C Somayajulu 
153711bcba0SDavid C Somayajulu 		device_printf(dev,
154711bcba0SDavid C Somayajulu 			"%s: (rxb->paddr != cq_e->b_paddr)[%p, %p] \n",
155711bcba0SDavid C Somayajulu 			__func__, (void *)rxb->paddr, (void *)cq_e->b_paddr);
156711bcba0SDavid C Somayajulu 
157711bcba0SDavid C Somayajulu 		Q81_SET_CQ_INVALID(cq_idx);
158711bcba0SDavid C Somayajulu 
159711bcba0SDavid C Somayajulu 		ha->qla_initiate_recovery = 1;
160711bcba0SDavid C Somayajulu 
161711bcba0SDavid C Somayajulu 		return(-1);
162711bcba0SDavid C Somayajulu 	}
163711bcba0SDavid C Somayajulu 
164711bcba0SDavid C Somayajulu 	rxr->rx_int++;
165711bcba0SDavid C Somayajulu 
166711bcba0SDavid C Somayajulu 	if ((cq_e->flags1 & Q81_RX_FLAGS1_ERR_MASK) == 0) {
167711bcba0SDavid C Somayajulu 
168711bcba0SDavid C Somayajulu 		mp = rxb->m_head;
169711bcba0SDavid C Somayajulu 		rxb->m_head = NULL;
170711bcba0SDavid C Somayajulu 
171711bcba0SDavid C Somayajulu 		if (mp == NULL) {
172711bcba0SDavid C Somayajulu 			device_printf(dev, "%s: mp == NULL\n", __func__);
173711bcba0SDavid C Somayajulu 		} else {
174711bcba0SDavid C Somayajulu 			mp->m_flags |= M_PKTHDR;
175711bcba0SDavid C Somayajulu 			mp->m_pkthdr.len = cq_e->length;
176711bcba0SDavid C Somayajulu 			mp->m_pkthdr.rcvif = ifp;
177711bcba0SDavid C Somayajulu 			mp->m_len = cq_e->length;
178711bcba0SDavid C Somayajulu 
179711bcba0SDavid C Somayajulu 			eh = mtod(mp, struct ether_vlan_header *);
180711bcba0SDavid C Somayajulu 
181711bcba0SDavid C Somayajulu 			if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
182711bcba0SDavid C Somayajulu 				uint32_t *data = (uint32_t *)eh;
183711bcba0SDavid C Somayajulu 
184711bcba0SDavid C Somayajulu 				mp->m_pkthdr.ether_vtag = ntohs(eh->evl_tag);
185711bcba0SDavid C Somayajulu 				mp->m_flags |= M_VLANTAG;
186711bcba0SDavid C Somayajulu 
187711bcba0SDavid C Somayajulu 				*(data + 3) = *(data + 2);
188711bcba0SDavid C Somayajulu 				*(data + 2) = *(data + 1);
189711bcba0SDavid C Somayajulu 				*(data + 1) = *data;
190711bcba0SDavid C Somayajulu 
191711bcba0SDavid C Somayajulu 				m_adj(mp, ETHER_VLAN_ENCAP_LEN);
192711bcba0SDavid C Somayajulu 			}
193711bcba0SDavid C Somayajulu 
194711bcba0SDavid C Somayajulu 			if ((cq_e->flags1 & Q81_RX_FLAGS1_RSS_MATCH_MASK)) {
195711bcba0SDavid C Somayajulu 				rxr->rss_int++;
196711bcba0SDavid C Somayajulu 				mp->m_pkthdr.flowid = cq_e->rss;
19736ad8372SSepherosa Ziehau 				M_HASHTYPE_SET(mp, M_HASHTYPE_OPAQUE_HASH);
198711bcba0SDavid C Somayajulu 			}
199711bcba0SDavid C Somayajulu 			if (cq_e->flags0 & (Q81_RX_FLAGS0_TE |
200711bcba0SDavid C Somayajulu 				Q81_RX_FLAGS0_NU | Q81_RX_FLAGS0_IE)) {
201711bcba0SDavid C Somayajulu 				mp->m_pkthdr.csum_flags = 0;
202711bcba0SDavid C Somayajulu 			} else {
203711bcba0SDavid C Somayajulu 				mp->m_pkthdr.csum_flags = CSUM_IP_CHECKED |
204711bcba0SDavid C Somayajulu 					CSUM_IP_VALID | CSUM_DATA_VALID |
205711bcba0SDavid C Somayajulu 					CSUM_PSEUDO_HDR;
206711bcba0SDavid C Somayajulu 				mp->m_pkthdr.csum_data = 0xFFFF;
207711bcba0SDavid C Somayajulu 			}
208c8dfaf38SGleb Smirnoff 			if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
209711bcba0SDavid C Somayajulu 
210711bcba0SDavid C Somayajulu 			if (lro->lro_cnt && (tcp_lro_rx(lro, mp, 0) == 0)) {
211453130d9SPedro F. Giffuni 				/* LRO packet has been successfully queued */
212711bcba0SDavid C Somayajulu 			} else {
213711bcba0SDavid C Somayajulu 				(*ifp->if_input)(ifp, mp);
214711bcba0SDavid C Somayajulu 			}
215711bcba0SDavid C Somayajulu 		}
216711bcba0SDavid C Somayajulu 	} else {
217711bcba0SDavid C Somayajulu 		device_printf(dev, "%s: err [0%08x]\n", __func__, cq_e->flags1);
218711bcba0SDavid C Somayajulu 	}
219711bcba0SDavid C Somayajulu 
220711bcba0SDavid C Somayajulu 	rxr->rx_free++;
221711bcba0SDavid C Somayajulu 	rxr->rx_next++;
222711bcba0SDavid C Somayajulu 
223711bcba0SDavid C Somayajulu 	if (rxr->rx_next == NUM_RX_DESCRIPTORS)
224711bcba0SDavid C Somayajulu 		rxr->rx_next = 0;
225711bcba0SDavid C Somayajulu 
226711bcba0SDavid C Somayajulu 	if ((rxr->rx_free + rxr->sbq_free) >= 16)
227711bcba0SDavid C Somayajulu                 qls_replenish_rx(ha, rxr_idx);
228711bcba0SDavid C Somayajulu 
229711bcba0SDavid C Somayajulu 	return 0;
230711bcba0SDavid C Somayajulu }
231711bcba0SDavid C Somayajulu 
232711bcba0SDavid C Somayajulu static void
233711bcba0SDavid C Somayajulu qls_cq_isr(qla_host_t *ha, uint32_t cq_idx)
234711bcba0SDavid C Somayajulu {
235711bcba0SDavid C Somayajulu 	q81_cq_e_t *cq_e, *cq_b;
236711bcba0SDavid C Somayajulu 	uint32_t i, cq_comp_idx;
237711bcba0SDavid C Somayajulu 	int ret = 0, tx_comp_done = 0;
238711bcba0SDavid C Somayajulu 	struct lro_ctrl	*lro;
239711bcba0SDavid C Somayajulu 
240711bcba0SDavid C Somayajulu 	cq_b = ha->rx_ring[cq_idx].cq_base_vaddr;
241711bcba0SDavid C Somayajulu 	lro = &ha->rx_ring[cq_idx].lro;
242711bcba0SDavid C Somayajulu 
243711bcba0SDavid C Somayajulu 	cq_comp_idx = *(ha->rx_ring[cq_idx].cqi_vaddr);
244711bcba0SDavid C Somayajulu 
245711bcba0SDavid C Somayajulu 	i = ha->rx_ring[cq_idx].cq_next;
246711bcba0SDavid C Somayajulu 
247711bcba0SDavid C Somayajulu 	while (i != cq_comp_idx) {
248711bcba0SDavid C Somayajulu 
249711bcba0SDavid C Somayajulu 		cq_e = &cq_b[i];
250711bcba0SDavid C Somayajulu 
251711bcba0SDavid C Somayajulu 		switch (cq_e->opcode) {
252711bcba0SDavid C Somayajulu 
253711bcba0SDavid C Somayajulu                 case Q81_IOCB_TX_MAC:
254711bcba0SDavid C Somayajulu                 case Q81_IOCB_TX_TSO:
255711bcba0SDavid C Somayajulu                         qls_tx_comp(ha, cq_idx, (q81_tx_mac_comp_t *)cq_e);
256711bcba0SDavid C Somayajulu                         tx_comp_done++;
257711bcba0SDavid C Somayajulu                         break;
258711bcba0SDavid C Somayajulu 
259711bcba0SDavid C Somayajulu 		case Q81_IOCB_RX:
260711bcba0SDavid C Somayajulu 			ret = qls_rx_comp(ha, cq_idx, i, (q81_rx_t *)cq_e);
261711bcba0SDavid C Somayajulu 
262711bcba0SDavid C Somayajulu 			break;
263711bcba0SDavid C Somayajulu 
264711bcba0SDavid C Somayajulu 		case Q81_IOCB_MPI:
265711bcba0SDavid C Somayajulu 		case Q81_IOCB_SYS:
266711bcba0SDavid C Somayajulu 		default:
267711bcba0SDavid C Somayajulu 			device_printf(ha->pci_dev, "%s[%d %d 0x%x]: illegal \n",
268711bcba0SDavid C Somayajulu 				__func__, i, (*(ha->rx_ring[cq_idx].cqi_vaddr)),
269711bcba0SDavid C Somayajulu 				cq_e->opcode);
270711bcba0SDavid C Somayajulu 			qls_dump_buf32(ha, __func__, cq_e,
271711bcba0SDavid C Somayajulu 				(sizeof (q81_cq_e_t) >> 2));
272711bcba0SDavid C Somayajulu 			break;
273711bcba0SDavid C Somayajulu 		}
274711bcba0SDavid C Somayajulu 
275711bcba0SDavid C Somayajulu 		i++;
276711bcba0SDavid C Somayajulu 		if (i == NUM_CQ_ENTRIES)
277711bcba0SDavid C Somayajulu 			i = 0;
278711bcba0SDavid C Somayajulu 
279711bcba0SDavid C Somayajulu 		if (ret) {
280711bcba0SDavid C Somayajulu 			break;
281711bcba0SDavid C Somayajulu 		}
282711bcba0SDavid C Somayajulu 
283711bcba0SDavid C Somayajulu 		if (i == cq_comp_idx) {
284711bcba0SDavid C Somayajulu 			cq_comp_idx = *(ha->rx_ring[cq_idx].cqi_vaddr);
285711bcba0SDavid C Somayajulu 		}
286711bcba0SDavid C Somayajulu 
287711bcba0SDavid C Somayajulu                 if (tx_comp_done) {
288711bcba0SDavid C Somayajulu                         taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
289711bcba0SDavid C Somayajulu                         tx_comp_done = 0;
290711bcba0SDavid C Somayajulu                 }
291711bcba0SDavid C Somayajulu 	}
292711bcba0SDavid C Somayajulu 
2936dd38b87SSepherosa Ziehau 	tcp_lro_flush_all(lro);
294711bcba0SDavid C Somayajulu 
295711bcba0SDavid C Somayajulu 	ha->rx_ring[cq_idx].cq_next = cq_comp_idx;
296711bcba0SDavid C Somayajulu 
297711bcba0SDavid C Somayajulu 	if (!ret) {
298711bcba0SDavid C Somayajulu 		Q81_WR_CQ_CONS_IDX(cq_idx, (ha->rx_ring[cq_idx].cq_next));
299711bcba0SDavid C Somayajulu 	}
300711bcba0SDavid C Somayajulu         if (tx_comp_done)
301711bcba0SDavid C Somayajulu                 taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
302711bcba0SDavid C Somayajulu 
303711bcba0SDavid C Somayajulu 	return;
304711bcba0SDavid C Somayajulu }
305711bcba0SDavid C Somayajulu 
306711bcba0SDavid C Somayajulu static void
307711bcba0SDavid C Somayajulu qls_mbx_isr(qla_host_t *ha)
308711bcba0SDavid C Somayajulu {
309711bcba0SDavid C Somayajulu 	uint32_t data;
310711bcba0SDavid C Somayajulu 	int i;
311711bcba0SDavid C Somayajulu 	device_t dev = ha->pci_dev;
312711bcba0SDavid C Somayajulu 
313711bcba0SDavid C Somayajulu 	if (qls_mbx_rd_reg(ha, 0, &data) == 0) {
314711bcba0SDavid C Somayajulu 
315711bcba0SDavid C Somayajulu 		if ((data & 0xF000) == 0x4000) {
316711bcba0SDavid C Somayajulu 			ha->mbox[0] = data;
317711bcba0SDavid C Somayajulu 			for (i = 1; i < Q81_NUM_MBX_REGISTERS; i++) {
318711bcba0SDavid C Somayajulu 				if (qls_mbx_rd_reg(ha, i, &data))
319711bcba0SDavid C Somayajulu 					break;
320711bcba0SDavid C Somayajulu 				ha->mbox[i] = data;
321711bcba0SDavid C Somayajulu 			}
322711bcba0SDavid C Somayajulu 			ha->mbx_done = 1;
323711bcba0SDavid C Somayajulu 		} else if ((data & 0xF000) == 0x8000) {
324711bcba0SDavid C Somayajulu 
325711bcba0SDavid C Somayajulu 			/* we have an AEN */
326711bcba0SDavid C Somayajulu 
327711bcba0SDavid C Somayajulu 			ha->aen[0] = data;
328711bcba0SDavid C Somayajulu 			for (i = 1; i < Q81_NUM_AEN_REGISTERS; i++) {
329711bcba0SDavid C Somayajulu 				if (qls_mbx_rd_reg(ha, i, &data))
330711bcba0SDavid C Somayajulu 					break;
331711bcba0SDavid C Somayajulu 				ha->aen[i] = data;
332711bcba0SDavid C Somayajulu 			}
333711bcba0SDavid C Somayajulu 			device_printf(dev,"%s: AEN "
334711bcba0SDavid C Somayajulu 				"[0x%08x 0x%08x 0x%08x 0x%08x 0x%08x"
335711bcba0SDavid C Somayajulu 				" 0x%08x 0x%08x 0x%08x 0x%08x]\n",
336711bcba0SDavid C Somayajulu 				__func__,
337711bcba0SDavid C Somayajulu 				ha->aen[0], ha->aen[1], ha->aen[2],
338711bcba0SDavid C Somayajulu 				ha->aen[3], ha->aen[4], ha->aen[5],
339711bcba0SDavid C Somayajulu 				ha->aen[6], ha->aen[7], ha->aen[8]);
340711bcba0SDavid C Somayajulu 
341711bcba0SDavid C Somayajulu 			switch ((ha->aen[0] & 0xFFFF)) {
342711bcba0SDavid C Somayajulu 
343711bcba0SDavid C Somayajulu 			case 0x8011:
344711bcba0SDavid C Somayajulu 				ha->link_up = 1;
345711bcba0SDavid C Somayajulu 				break;
346711bcba0SDavid C Somayajulu 
347711bcba0SDavid C Somayajulu 			case 0x8012:
348711bcba0SDavid C Somayajulu 				ha->link_up = 0;
349711bcba0SDavid C Somayajulu 				break;
350711bcba0SDavid C Somayajulu 
351711bcba0SDavid C Somayajulu 			case 0x8130:
352711bcba0SDavid C Somayajulu 				ha->link_hw_info = ha->aen[1];
353711bcba0SDavid C Somayajulu 				break;
354711bcba0SDavid C Somayajulu 
355711bcba0SDavid C Somayajulu 			case 0x8131:
356711bcba0SDavid C Somayajulu 				ha->link_hw_info = 0;
357711bcba0SDavid C Somayajulu 				break;
358711bcba0SDavid C Somayajulu 
359711bcba0SDavid C Somayajulu 			}
360711bcba0SDavid C Somayajulu 		}
361711bcba0SDavid C Somayajulu 	}
362711bcba0SDavid C Somayajulu 	WRITE_REG32(ha, Q81_CTL_HOST_CMD_STATUS, Q81_CTL_HCS_CMD_CLR_RTH_INTR);
363711bcba0SDavid C Somayajulu 
364711bcba0SDavid C Somayajulu 	return;
365711bcba0SDavid C Somayajulu }
366711bcba0SDavid C Somayajulu 
367711bcba0SDavid C Somayajulu void
368711bcba0SDavid C Somayajulu qls_isr(void *arg)
369711bcba0SDavid C Somayajulu {
370711bcba0SDavid C Somayajulu 	qla_ivec_t *ivec = arg;
371711bcba0SDavid C Somayajulu 	qla_host_t *ha;
372711bcba0SDavid C Somayajulu 	uint32_t status;
373711bcba0SDavid C Somayajulu 	uint32_t cq_idx;
374711bcba0SDavid C Somayajulu 	device_t dev;
375711bcba0SDavid C Somayajulu 
376711bcba0SDavid C Somayajulu 	ha = ivec->ha;
377711bcba0SDavid C Somayajulu 	cq_idx = ivec->cq_idx;
378711bcba0SDavid C Somayajulu 	dev = ha->pci_dev;
379711bcba0SDavid C Somayajulu 
380711bcba0SDavid C Somayajulu 	status = READ_REG32(ha, Q81_CTL_STATUS);
381711bcba0SDavid C Somayajulu 
382711bcba0SDavid C Somayajulu 	if (status & Q81_CTL_STATUS_FE) {
383711bcba0SDavid C Somayajulu 		device_printf(dev, "%s fatal error\n", __func__);
384711bcba0SDavid C Somayajulu 		return;
385711bcba0SDavid C Somayajulu 	}
386711bcba0SDavid C Somayajulu 
387711bcba0SDavid C Somayajulu 	if ((cq_idx == 0) && (status & Q81_CTL_STATUS_PI)) {
388711bcba0SDavid C Somayajulu 		qls_mbx_isr(ha);
389711bcba0SDavid C Somayajulu 	}
390711bcba0SDavid C Somayajulu 
391711bcba0SDavid C Somayajulu 	status = READ_REG32(ha, Q81_CTL_INTR_STATUS1);
392711bcba0SDavid C Somayajulu 
393711bcba0SDavid C Somayajulu 	if (status & ( 0x1 << cq_idx))
394711bcba0SDavid C Somayajulu 		qls_cq_isr(ha, cq_idx);
395711bcba0SDavid C Somayajulu 
396711bcba0SDavid C Somayajulu 	Q81_ENABLE_INTR(ha, cq_idx);
397711bcba0SDavid C Somayajulu 
398711bcba0SDavid C Somayajulu 	return;
399711bcba0SDavid C Somayajulu }
400711bcba0SDavid C Somayajulu 
401