1250661Sdavidcs/*
2250661Sdavidcs * Copyright (c) 2013-2014 Qlogic Corporation
3250661Sdavidcs * All rights reserved.
4250661Sdavidcs *
5250661Sdavidcs *  Redistribution and use in source and binary forms, with or without
6250661Sdavidcs *  modification, are permitted provided that the following conditions
7250661Sdavidcs *  are met:
8250661Sdavidcs *
9250661Sdavidcs *  1. Redistributions of source code must retain the above copyright
10250661Sdavidcs *     notice, this list of conditions and the following disclaimer.
11250661Sdavidcs *  2. Redistributions in binary form must reproduce the above copyright
12250661Sdavidcs *     notice, this list of conditions and the following disclaimer in the
13250661Sdavidcs *     documentation and/or other materials provided with the distribution.
14250661Sdavidcs *
15250661Sdavidcs *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16250661Sdavidcs *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17250661Sdavidcs *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18250661Sdavidcs *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19250661Sdavidcs *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20250661Sdavidcs *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21250661Sdavidcs *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22250661Sdavidcs *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23250661Sdavidcs *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24250661Sdavidcs *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25250661Sdavidcs *  POSSIBILITY OF SUCH DAMAGE.
26250661Sdavidcs */
27250661Sdavidcs
28250661Sdavidcs/*
29250661Sdavidcs * File: ql_isr.c
30250661Sdavidcs * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656.
31250661Sdavidcs */
32250661Sdavidcs
33250661Sdavidcs#include <sys/cdefs.h>
34250661Sdavidcs__FBSDID("$FreeBSD$");
35250661Sdavidcs
36250661Sdavidcs
37250661Sdavidcs#include "ql_os.h"
38250661Sdavidcs#include "ql_hw.h"
39250661Sdavidcs#include "ql_def.h"
40250661Sdavidcs#include "ql_inline.h"
41250661Sdavidcs#include "ql_ver.h"
42250661Sdavidcs#include "ql_glbl.h"
43250661Sdavidcs#include "ql_dbg.h"
44250661Sdavidcs
45250661Sdavidcsstatic void qla_replenish_normal_rx(qla_host_t *ha, qla_sds_t *sdsp,
46250661Sdavidcs		uint32_t r_idx);
47250661Sdavidcs
48250661Sdavidcsstatic void
49250661Sdavidcsqla_rcv_error(qla_host_t *ha)
50250661Sdavidcs{
51250661Sdavidcs	ha->flags.stop_rcv = 1;
52250661Sdavidcs	ha->qla_initiate_recovery = 1;
53250661Sdavidcs}
54250661Sdavidcs
55250661Sdavidcs
56250661Sdavidcs/*
57250661Sdavidcs * Name: qla_rx_intr
58250661Sdavidcs * Function: Handles normal ethernet frames received
59250661Sdavidcs */
60250661Sdavidcsstatic void
61250661Sdavidcsqla_rx_intr(qla_host_t *ha, qla_sgl_rcv_t *sgc, uint32_t sds_idx)
62250661Sdavidcs{
63250661Sdavidcs	qla_rx_buf_t		*rxb;
64250661Sdavidcs	struct mbuf		*mp = NULL, *mpf = NULL, *mpl = NULL;
65250661Sdavidcs	struct ifnet		*ifp = ha->ifp;
66250661Sdavidcs	qla_sds_t		*sdsp;
67250661Sdavidcs	struct ether_vlan_header *eh;
68250661Sdavidcs	uint32_t		i, rem_len = 0;
69250661Sdavidcs	uint32_t		r_idx = 0;
70250661Sdavidcs	qla_rx_ring_t		*rx_ring;
71250661Sdavidcs
72250661Sdavidcs	if (ha->hw.num_rds_rings > 1)
73250661Sdavidcs		r_idx = sds_idx;
74250661Sdavidcs
75250661Sdavidcs	ha->hw.rds[r_idx].count++;
76250661Sdavidcs
77250661Sdavidcs	sdsp = &ha->hw.sds[sds_idx];
78250661Sdavidcs	rx_ring = &ha->rx_ring[r_idx];
79250661Sdavidcs
80250661Sdavidcs	for (i = 0; i < sgc->num_handles; i++) {
81250661Sdavidcs		rxb = &rx_ring->rx_buf[sgc->handle[i] & 0x7FFF];
82250661Sdavidcs
83250661Sdavidcs		QL_ASSERT(ha, (rxb != NULL),
84250661Sdavidcs			("%s: [sds_idx]=[%d] rxb != NULL\n", __func__,\
85250661Sdavidcs			sds_idx));
86250661Sdavidcs
87250661Sdavidcs		if ((rxb == NULL) || QL_ERR_INJECT(ha, INJCT_RX_RXB_INVAL)) {
88250661Sdavidcs			/* log the error */
89250661Sdavidcs			device_printf(ha->pci_dev,
90250661Sdavidcs				"%s invalid rxb[%d, %d, 0x%04x]\n",
91250661Sdavidcs				__func__, sds_idx, i, sgc->handle[i]);
92250661Sdavidcs			qla_rcv_error(ha);
93250661Sdavidcs			return;
94250661Sdavidcs		}
95250661Sdavidcs
96250661Sdavidcs		mp = rxb->m_head;
97250661Sdavidcs		if (i == 0)
98250661Sdavidcs			mpf = mp;
99250661Sdavidcs
100250661Sdavidcs		QL_ASSERT(ha, (mp != NULL),
101250661Sdavidcs			("%s: [sds_idx]=[%d] mp != NULL\n", __func__,\
102250661Sdavidcs			sds_idx));
103250661Sdavidcs
104250661Sdavidcs		bus_dmamap_sync(ha->rx_tag, rxb->map, BUS_DMASYNC_POSTREAD);
105250661Sdavidcs
106250661Sdavidcs		rxb->m_head = NULL;
107250661Sdavidcs		rxb->next = sdsp->rxb_free;
108250661Sdavidcs		sdsp->rxb_free = rxb;
109250661Sdavidcs		sdsp->rx_free++;
110250661Sdavidcs
111250661Sdavidcs		if ((mp == NULL) || QL_ERR_INJECT(ha, INJCT_RX_MP_NULL)) {
112250661Sdavidcs			/* log the error */
113250661Sdavidcs			device_printf(ha->pci_dev,
114250661Sdavidcs				"%s mp  == NULL [%d, %d, 0x%04x]\n",
115250661Sdavidcs				__func__, sds_idx, i, sgc->handle[i]);
116250661Sdavidcs			qla_rcv_error(ha);
117250661Sdavidcs			return;
118250661Sdavidcs		}
119250661Sdavidcs
120250661Sdavidcs		if (i == 0) {
121250661Sdavidcs			mpl = mpf = mp;
122250661Sdavidcs			mp->m_flags |= M_PKTHDR;
123250661Sdavidcs			mp->m_pkthdr.len = sgc->pkt_length;
124250661Sdavidcs			mp->m_pkthdr.rcvif = ifp;
125250661Sdavidcs			rem_len = mp->m_pkthdr.len;
126250661Sdavidcs		} else {
127250661Sdavidcs			mp->m_flags &= ~M_PKTHDR;
128250661Sdavidcs			mpl->m_next = mp;
129250661Sdavidcs			mpl = mp;
130250661Sdavidcs			rem_len = rem_len - mp->m_len;
131250661Sdavidcs		}
132250661Sdavidcs	}
133250661Sdavidcs
134250661Sdavidcs	mpl->m_len = rem_len;
135250661Sdavidcs
136250661Sdavidcs	eh = mtod(mpf, struct ether_vlan_header *);
137250661Sdavidcs
138250661Sdavidcs	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
139250661Sdavidcs		uint32_t *data = (uint32_t *)eh;
140250661Sdavidcs
141250661Sdavidcs		mpf->m_pkthdr.ether_vtag = ntohs(eh->evl_tag);
142250661Sdavidcs		mpf->m_flags |= M_VLANTAG;
143250661Sdavidcs
144250661Sdavidcs		*(data + 3) = *(data + 2);
145250661Sdavidcs		*(data + 2) = *(data + 1);
146250661Sdavidcs		*(data + 1) = *data;
147250661Sdavidcs
148250661Sdavidcs		m_adj(mpf, ETHER_VLAN_ENCAP_LEN);
149250661Sdavidcs	}
150250661Sdavidcs
151250661Sdavidcs	if (sgc->chksum_status == Q8_STAT_DESC_STATUS_CHKSUM_OK) {
152250661Sdavidcs		mpf->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID |
153250661Sdavidcs			CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
154250661Sdavidcs		mpf->m_pkthdr.csum_data = 0xFFFF;
155250661Sdavidcs	} else {
156250661Sdavidcs		mpf->m_pkthdr.csum_flags = 0;
157250661Sdavidcs	}
158250661Sdavidcs
159250661Sdavidcs	ifp->if_ipackets++;
160250661Sdavidcs
161250661Sdavidcs	mpf->m_pkthdr.flowid = sgc->rss_hash;
162250661Sdavidcs	mpf->m_flags |= M_FLOWID;
163250661Sdavidcs
164250661Sdavidcs	(*ifp->if_input)(ifp, mpf);
165250661Sdavidcs
166250661Sdavidcs	if (sdsp->rx_free > ha->std_replenish)
167250661Sdavidcs		qla_replenish_normal_rx(ha, sdsp, r_idx);
168250661Sdavidcs
169250661Sdavidcs	return;
170250661Sdavidcs}
171250661Sdavidcs
172250661Sdavidcs#define QLA_TCP_HDR_SIZE        20
173250661Sdavidcs#define QLA_TCP_TS_OPTION_SIZE  12
174250661Sdavidcs
175250661Sdavidcs/*
176250661Sdavidcs * Name: qla_lro_intr
177250661Sdavidcs * Function: Handles normal ethernet frames received
178250661Sdavidcs */
179250661Sdavidcsstatic int
180250661Sdavidcsqla_lro_intr(qla_host_t *ha, qla_sgl_lro_t *sgc, uint32_t sds_idx)
181250661Sdavidcs{
182250661Sdavidcs	qla_rx_buf_t *rxb;
183250661Sdavidcs	struct mbuf *mp = NULL, *mpf = NULL, *mpl = NULL;
184250661Sdavidcs	struct ifnet *ifp = ha->ifp;
185250661Sdavidcs	qla_sds_t *sdsp;
186250661Sdavidcs	struct ether_vlan_header *eh;
187250661Sdavidcs	uint32_t i, rem_len = 0, pkt_length, iplen;
188250661Sdavidcs	struct tcphdr *th;
189250661Sdavidcs	struct ip *ip = NULL;
190250661Sdavidcs	struct ip6_hdr *ip6 = NULL;
191250661Sdavidcs	uint16_t etype;
192250661Sdavidcs	uint32_t r_idx = 0;
193250661Sdavidcs	qla_rx_ring_t *rx_ring;
194250661Sdavidcs
195250661Sdavidcs	if (ha->hw.num_rds_rings > 1)
196250661Sdavidcs		r_idx = sds_idx;
197250661Sdavidcs
198250661Sdavidcs	ha->hw.rds[r_idx].count++;
199250661Sdavidcs
200250661Sdavidcs	rx_ring = &ha->rx_ring[r_idx];
201250661Sdavidcs
202250661Sdavidcs	ha->lro_pkt_count++;
203250661Sdavidcs
204250661Sdavidcs	sdsp = &ha->hw.sds[sds_idx];
205250661Sdavidcs
206250661Sdavidcs	pkt_length = sgc->payload_length + sgc->l4_offset;
207250661Sdavidcs
208250661Sdavidcs	if (sgc->flags & Q8_LRO_COMP_TS) {
209250661Sdavidcs		pkt_length += QLA_TCP_HDR_SIZE + QLA_TCP_TS_OPTION_SIZE;
210250661Sdavidcs	} else {
211250661Sdavidcs		pkt_length += QLA_TCP_HDR_SIZE;
212250661Sdavidcs	}
213250661Sdavidcs	ha->lro_bytes += pkt_length;
214250661Sdavidcs
215250661Sdavidcs	for (i = 0; i < sgc->num_handles; i++) {
216250661Sdavidcs		rxb = &rx_ring->rx_buf[sgc->handle[i] & 0x7FFF];
217250661Sdavidcs
218250661Sdavidcs		QL_ASSERT(ha, (rxb != NULL),
219250661Sdavidcs			("%s: [sds_idx]=[%d] rxb != NULL\n", __func__,\
220250661Sdavidcs			sds_idx));
221250661Sdavidcs
222250661Sdavidcs		if ((rxb == NULL) || QL_ERR_INJECT(ha, INJCT_LRO_RXB_INVAL)) {
223250661Sdavidcs			/* log the error */
224250661Sdavidcs			device_printf(ha->pci_dev,
225250661Sdavidcs				"%s invalid rxb[%d, %d, 0x%04x]\n",
226250661Sdavidcs				__func__, sds_idx, i, sgc->handle[i]);
227250661Sdavidcs			qla_rcv_error(ha);
228250661Sdavidcs			return (0);
229250661Sdavidcs		}
230250661Sdavidcs
231250661Sdavidcs		mp = rxb->m_head;
232250661Sdavidcs		if (i == 0)
233250661Sdavidcs			mpf = mp;
234250661Sdavidcs
235250661Sdavidcs		QL_ASSERT(ha, (mp != NULL),
236250661Sdavidcs			("%s: [sds_idx]=[%d] mp != NULL\n", __func__,\
237250661Sdavidcs			sds_idx));
238250661Sdavidcs
239250661Sdavidcs		bus_dmamap_sync(ha->rx_tag, rxb->map, BUS_DMASYNC_POSTREAD);
240250661Sdavidcs
241250661Sdavidcs		rxb->m_head = NULL;
242250661Sdavidcs		rxb->next = sdsp->rxb_free;
243250661Sdavidcs		sdsp->rxb_free = rxb;
244250661Sdavidcs		sdsp->rx_free++;
245250661Sdavidcs
246250661Sdavidcs		if ((mp == NULL) || QL_ERR_INJECT(ha, INJCT_LRO_MP_NULL)) {
247250661Sdavidcs			/* log the error */
248250661Sdavidcs			device_printf(ha->pci_dev,
249250661Sdavidcs				"%s mp  == NULL [%d, %d, 0x%04x]\n",
250250661Sdavidcs				__func__, sds_idx, i, sgc->handle[i]);
251250661Sdavidcs			qla_rcv_error(ha);
252250661Sdavidcs			return (0);
253250661Sdavidcs		}
254250661Sdavidcs
255250661Sdavidcs		if (i == 0) {
256250661Sdavidcs			mpl = mpf = mp;
257250661Sdavidcs			mp->m_flags |= M_PKTHDR;
258250661Sdavidcs			mp->m_pkthdr.len = pkt_length;
259250661Sdavidcs			mp->m_pkthdr.rcvif = ifp;
260250661Sdavidcs			rem_len = mp->m_pkthdr.len;
261250661Sdavidcs		} else {
262250661Sdavidcs			mp->m_flags &= ~M_PKTHDR;
263250661Sdavidcs			mpl->m_next = mp;
264250661Sdavidcs			mpl = mp;
265250661Sdavidcs			rem_len = rem_len - mp->m_len;
266250661Sdavidcs		}
267250661Sdavidcs	}
268250661Sdavidcs
269250661Sdavidcs	mpl->m_len = rem_len;
270250661Sdavidcs
271250661Sdavidcs	th = (struct tcphdr *)(mpf->m_data + sgc->l4_offset);
272250661Sdavidcs
273250661Sdavidcs	if (sgc->flags & Q8_LRO_COMP_PUSH_BIT)
274250661Sdavidcs		th->th_flags |= TH_PUSH;
275250661Sdavidcs
276250661Sdavidcs	m_adj(mpf, sgc->l2_offset);
277250661Sdavidcs
278250661Sdavidcs	eh = mtod(mpf, struct ether_vlan_header *);
279250661Sdavidcs
280250661Sdavidcs	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
281250661Sdavidcs		uint32_t *data = (uint32_t *)eh;
282250661Sdavidcs
283250661Sdavidcs		mpf->m_pkthdr.ether_vtag = ntohs(eh->evl_tag);
284250661Sdavidcs		mpf->m_flags |= M_VLANTAG;
285250661Sdavidcs
286250661Sdavidcs		*(data + 3) = *(data + 2);
287250661Sdavidcs		*(data + 2) = *(data + 1);
288250661Sdavidcs		*(data + 1) = *data;
289250661Sdavidcs
290250661Sdavidcs		m_adj(mpf, ETHER_VLAN_ENCAP_LEN);
291250661Sdavidcs
292250661Sdavidcs		etype = ntohs(eh->evl_proto);
293250661Sdavidcs	} else {
294250661Sdavidcs		etype = ntohs(eh->evl_encap_proto);
295250661Sdavidcs	}
296250661Sdavidcs
297250661Sdavidcs	if (etype == ETHERTYPE_IP) {
298250661Sdavidcs		ip = (struct ip *)(mpf->m_data + ETHER_HDR_LEN);
299250661Sdavidcs
300250661Sdavidcs		iplen = (ip->ip_hl << 2) + (th->th_off << 2) +
301250661Sdavidcs				sgc->payload_length;
302250661Sdavidcs
303250661Sdavidcs                ip->ip_len = htons(iplen);
304250661Sdavidcs
305250661Sdavidcs		ha->ipv4_lro++;
306250661Sdavidcs	} else if (etype == ETHERTYPE_IPV6) {
307250661Sdavidcs		ip6 = (struct ip6_hdr *)(mpf->m_data + ETHER_HDR_LEN);
308250661Sdavidcs
309250661Sdavidcs		iplen = (th->th_off << 2) + sgc->payload_length;
310250661Sdavidcs
311250661Sdavidcs		ip6->ip6_plen = htons(iplen);
312250661Sdavidcs
313250661Sdavidcs		ha->ipv6_lro++;
314250661Sdavidcs	} else {
315250661Sdavidcs		m_freem(mpf);
316250661Sdavidcs
317250661Sdavidcs		if (sdsp->rx_free > ha->std_replenish)
318250661Sdavidcs			qla_replenish_normal_rx(ha, sdsp, r_idx);
319250661Sdavidcs		return 0;
320250661Sdavidcs	}
321250661Sdavidcs
322250661Sdavidcs	mpf->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID |
323250661Sdavidcs					CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
324250661Sdavidcs	mpf->m_pkthdr.csum_data = 0xFFFF;
325250661Sdavidcs
326250661Sdavidcs	mpf->m_pkthdr.flowid = sgc->rss_hash;
327250661Sdavidcs	mpf->m_flags |= M_FLOWID;
328250661Sdavidcs
329250661Sdavidcs	ifp->if_ipackets++;
330250661Sdavidcs
331250661Sdavidcs	(*ifp->if_input)(ifp, mpf);
332250661Sdavidcs
333250661Sdavidcs	if (sdsp->rx_free > ha->std_replenish)
334250661Sdavidcs		qla_replenish_normal_rx(ha, sdsp, r_idx);
335250661Sdavidcs
336250661Sdavidcs	return (0);
337250661Sdavidcs}
338250661Sdavidcs
339250661Sdavidcsstatic int
340250661Sdavidcsqla_rcv_cont_sds(qla_host_t *ha, uint32_t sds_idx, uint32_t comp_idx,
341250661Sdavidcs	uint32_t dcount, uint16_t *handle, uint16_t *nhandles)
342250661Sdavidcs{
343250661Sdavidcs	uint32_t i;
344250661Sdavidcs	uint16_t num_handles;
345250661Sdavidcs	q80_stat_desc_t *sdesc;
346250661Sdavidcs	uint32_t opcode;
347250661Sdavidcs
348250661Sdavidcs	*nhandles = 0;
349250661Sdavidcs	dcount--;
350250661Sdavidcs
351250661Sdavidcs	for (i = 0; i < dcount; i++) {
352250661Sdavidcs		comp_idx = (comp_idx + 1) & (NUM_STATUS_DESCRIPTORS-1);
353250661Sdavidcs		sdesc = (q80_stat_desc_t *)
354250661Sdavidcs				&ha->hw.sds[sds_idx].sds_ring_base[comp_idx];
355250661Sdavidcs
356250661Sdavidcs		opcode = Q8_STAT_DESC_OPCODE((sdesc->data[1]));
357250661Sdavidcs
358250661Sdavidcs		if (!opcode) {
359250661Sdavidcs			device_printf(ha->pci_dev, "%s: opcode=0 %p %p\n",
360250661Sdavidcs				__func__, (void *)sdesc->data[0],
361250661Sdavidcs				(void *)sdesc->data[1]);
362250661Sdavidcs			return -1;
363250661Sdavidcs		}
364250661Sdavidcs
365250661Sdavidcs		num_handles = Q8_SGL_STAT_DESC_NUM_HANDLES((sdesc->data[1]));
366250661Sdavidcs		if (!num_handles) {
367250661Sdavidcs			device_printf(ha->pci_dev, "%s: opcode=0 %p %p\n",
368250661Sdavidcs				__func__, (void *)sdesc->data[0],
369250661Sdavidcs				(void *)sdesc->data[1]);
370250661Sdavidcs			return -1;
371250661Sdavidcs		}
372250661Sdavidcs
373250661Sdavidcs		if (QL_ERR_INJECT(ha, INJCT_NUM_HNDLE_INVALID))
374250661Sdavidcs			num_handles = -1;
375250661Sdavidcs
376250661Sdavidcs		switch (num_handles) {
377250661Sdavidcs
378250661Sdavidcs		case 1:
379250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
380250661Sdavidcs			break;
381250661Sdavidcs
382250661Sdavidcs		case 2:
383250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
384250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE2((sdesc->data[0]));
385250661Sdavidcs			break;
386250661Sdavidcs
387250661Sdavidcs		case 3:
388250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
389250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE2((sdesc->data[0]));
390250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE3((sdesc->data[0]));
391250661Sdavidcs			break;
392250661Sdavidcs
393250661Sdavidcs		case 4:
394250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
395250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE2((sdesc->data[0]));
396250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE3((sdesc->data[0]));
397250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE4((sdesc->data[0]));
398250661Sdavidcs			break;
399250661Sdavidcs
400250661Sdavidcs		case 5:
401250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
402250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE2((sdesc->data[0]));
403250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE3((sdesc->data[0]));
404250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE4((sdesc->data[0]));
405250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE5((sdesc->data[1]));
406250661Sdavidcs			break;
407250661Sdavidcs
408250661Sdavidcs		case 6:
409250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
410250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE2((sdesc->data[0]));
411250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE3((sdesc->data[0]));
412250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE4((sdesc->data[0]));
413250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE5((sdesc->data[1]));
414250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE6((sdesc->data[1]));
415250661Sdavidcs			break;
416250661Sdavidcs
417250661Sdavidcs		case 7:
418250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
419250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE2((sdesc->data[0]));
420250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE3((sdesc->data[0]));
421250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE4((sdesc->data[0]));
422250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE5((sdesc->data[1]));
423250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE6((sdesc->data[1]));
424250661Sdavidcs			*handle++ = Q8_SGL_STAT_DESC_HANDLE7((sdesc->data[1]));
425250661Sdavidcs			break;
426250661Sdavidcs
427250661Sdavidcs		default:
428250661Sdavidcs			device_printf(ha->pci_dev,
429250661Sdavidcs				"%s: invalid num handles %p %p\n",
430250661Sdavidcs				__func__, (void *)sdesc->data[0],
431250661Sdavidcs				(void *)sdesc->data[1]);
432250661Sdavidcs
433250661Sdavidcs			QL_ASSERT(ha, (0),\
434250661Sdavidcs			("%s: %s [nh, sds, d0, d1]=[%d, %d, %p, %p]\n",
435250661Sdavidcs			__func__, "invalid num handles", sds_idx, num_handles,
436250661Sdavidcs			(void *)sdesc->data[0],(void *)sdesc->data[1]));
437250661Sdavidcs
438250661Sdavidcs			qla_rcv_error(ha);
439250661Sdavidcs			return 0;
440250661Sdavidcs		}
441250661Sdavidcs		*nhandles = *nhandles + num_handles;
442250661Sdavidcs	}
443250661Sdavidcs	return 0;
444250661Sdavidcs}
445250661Sdavidcs
446250661Sdavidcs/*
447250661Sdavidcs * Name: qla_rcv_isr
448250661Sdavidcs * Function: Main Interrupt Service Routine
449250661Sdavidcs */
450250661Sdavidcsstatic uint32_t
451250661Sdavidcsqla_rcv_isr(qla_host_t *ha, uint32_t sds_idx, uint32_t count)
452250661Sdavidcs{
453250661Sdavidcs	device_t dev;
454250661Sdavidcs	qla_hw_t *hw;
455250661Sdavidcs	uint32_t comp_idx, c_idx = 0, desc_count = 0, opcode;
456250661Sdavidcs	volatile q80_stat_desc_t *sdesc, *sdesc0 = NULL;
457250661Sdavidcs	uint32_t ret = 0;
458250661Sdavidcs	qla_sgl_comp_t sgc;
459250661Sdavidcs	uint16_t nhandles;
460250661Sdavidcs	uint32_t sds_replenish_threshold = 0;
461250661Sdavidcs
462250661Sdavidcs	dev = ha->pci_dev;
463250661Sdavidcs	hw = &ha->hw;
464250661Sdavidcs
465250661Sdavidcs	hw->sds[sds_idx].rcv_active = 1;
466250661Sdavidcs	if (ha->flags.stop_rcv) {
467250661Sdavidcs		hw->sds[sds_idx].rcv_active = 0;
468250661Sdavidcs		return 0;
469250661Sdavidcs	}
470250661Sdavidcs
471250661Sdavidcs	QL_DPRINT2(ha, (dev, "%s: [%d]enter\n", __func__, sds_idx));
472250661Sdavidcs
473250661Sdavidcs	/*
474250661Sdavidcs	 * receive interrupts
475250661Sdavidcs	 */
476250661Sdavidcs	comp_idx = hw->sds[sds_idx].sdsr_next;
477250661Sdavidcs
478250661Sdavidcs	while (count-- && !ha->flags.stop_rcv) {
479250661Sdavidcs
480250661Sdavidcs		sdesc = (q80_stat_desc_t *)
481250661Sdavidcs				&hw->sds[sds_idx].sds_ring_base[comp_idx];
482250661Sdavidcs
483250661Sdavidcs		opcode = Q8_STAT_DESC_OPCODE((sdesc->data[1]));
484250661Sdavidcs
485250661Sdavidcs		if (!opcode)
486250661Sdavidcs			break;
487250661Sdavidcs
488250661Sdavidcs		hw->sds[sds_idx].intr_count++;
489250661Sdavidcs		switch (opcode) {
490250661Sdavidcs
491250661Sdavidcs		case Q8_STAT_DESC_OPCODE_RCV_PKT:
492250661Sdavidcs
493250661Sdavidcs			desc_count = 1;
494250661Sdavidcs
495250661Sdavidcs			bzero(&sgc, sizeof(qla_sgl_comp_t));
496250661Sdavidcs
497250661Sdavidcs			sgc.rcv.pkt_length =
498250661Sdavidcs				Q8_STAT_DESC_TOTAL_LENGTH((sdesc->data[0]));
499250661Sdavidcs			sgc.rcv.num_handles = 1;
500250661Sdavidcs			sgc.rcv.handle[0] =
501250661Sdavidcs				Q8_STAT_DESC_HANDLE((sdesc->data[0]));
502250661Sdavidcs			sgc.rcv.chksum_status =
503250661Sdavidcs				Q8_STAT_DESC_STATUS((sdesc->data[1]));
504250661Sdavidcs
505250661Sdavidcs			sgc.rcv.rss_hash =
506250661Sdavidcs				Q8_STAT_DESC_RSS_HASH((sdesc->data[0]));
507250661Sdavidcs
508250661Sdavidcs			if (Q8_STAT_DESC_VLAN((sdesc->data[1]))) {
509250661Sdavidcs				sgc.rcv.vlan_tag =
510250661Sdavidcs					Q8_STAT_DESC_VLAN_ID((sdesc->data[1]));
511250661Sdavidcs			}
512250661Sdavidcs			qla_rx_intr(ha, &sgc.rcv, sds_idx);
513250661Sdavidcs			break;
514250661Sdavidcs
515250661Sdavidcs		case Q8_STAT_DESC_OPCODE_SGL_RCV:
516250661Sdavidcs
517250661Sdavidcs			desc_count =
518250661Sdavidcs				Q8_STAT_DESC_COUNT_SGL_RCV((sdesc->data[1]));
519250661Sdavidcs
520250661Sdavidcs			if (desc_count > 1) {
521250661Sdavidcs				c_idx = (comp_idx + desc_count -1) &
522250661Sdavidcs						(NUM_STATUS_DESCRIPTORS-1);
523250661Sdavidcs				sdesc0 = (q80_stat_desc_t *)
524250661Sdavidcs					&hw->sds[sds_idx].sds_ring_base[c_idx];
525250661Sdavidcs
526250661Sdavidcs				if (Q8_STAT_DESC_OPCODE((sdesc0->data[1])) !=
527250661Sdavidcs						Q8_STAT_DESC_OPCODE_CONT) {
528250661Sdavidcs					desc_count = 0;
529250661Sdavidcs					break;
530250661Sdavidcs				}
531250661Sdavidcs			}
532250661Sdavidcs
533250661Sdavidcs			bzero(&sgc, sizeof(qla_sgl_comp_t));
534250661Sdavidcs
535250661Sdavidcs			sgc.rcv.pkt_length =
536250661Sdavidcs				Q8_STAT_DESC_TOTAL_LENGTH_SGL_RCV(\
537250661Sdavidcs					(sdesc->data[0]));
538250661Sdavidcs			sgc.rcv.chksum_status =
539250661Sdavidcs				Q8_STAT_DESC_STATUS((sdesc->data[1]));
540250661Sdavidcs
541250661Sdavidcs			sgc.rcv.rss_hash =
542250661Sdavidcs				Q8_STAT_DESC_RSS_HASH((sdesc->data[0]));
543250661Sdavidcs
544250661Sdavidcs			if (Q8_STAT_DESC_VLAN((sdesc->data[1]))) {
545250661Sdavidcs				sgc.rcv.vlan_tag =
546250661Sdavidcs					Q8_STAT_DESC_VLAN_ID((sdesc->data[1]));
547250661Sdavidcs			}
548250661Sdavidcs
549250661Sdavidcs			QL_ASSERT(ha, (desc_count <= 2) ,\
550250661Sdavidcs				("%s: [sds_idx, data0, data1]="\
551250661Sdavidcs				"%d, %p, %p]\n", __func__, sds_idx,\
552250661Sdavidcs				(void *)sdesc->data[0],\
553250661Sdavidcs				(void *)sdesc->data[1]));
554250661Sdavidcs
555250661Sdavidcs			sgc.rcv.num_handles = 1;
556250661Sdavidcs			sgc.rcv.handle[0] =
557250661Sdavidcs				Q8_STAT_DESC_HANDLE((sdesc->data[0]));
558250661Sdavidcs
559250661Sdavidcs			if (qla_rcv_cont_sds(ha, sds_idx, comp_idx, desc_count,
560250661Sdavidcs				&sgc.rcv.handle[1], &nhandles)) {
561250661Sdavidcs				device_printf(dev,
562250661Sdavidcs					"%s: [sds_idx, dcount, data0, data1]="
563250661Sdavidcs					 "[%d, %d, 0x%llx, 0x%llx]\n",
564250661Sdavidcs					__func__, sds_idx, desc_count,
565250661Sdavidcs					(long long unsigned int)sdesc->data[0],
566250661Sdavidcs					(long long unsigned int)sdesc->data[1]);
567250661Sdavidcs				desc_count = 0;
568250661Sdavidcs				break;
569250661Sdavidcs			}
570250661Sdavidcs
571250661Sdavidcs			sgc.rcv.num_handles += nhandles;
572250661Sdavidcs
573250661Sdavidcs			qla_rx_intr(ha, &sgc.rcv, sds_idx);
574250661Sdavidcs
575250661Sdavidcs			break;
576250661Sdavidcs
577250661Sdavidcs		case Q8_STAT_DESC_OPCODE_SGL_LRO:
578250661Sdavidcs
579250661Sdavidcs			desc_count =
580250661Sdavidcs				Q8_STAT_DESC_COUNT_SGL_LRO((sdesc->data[1]));
581250661Sdavidcs
582250661Sdavidcs			if (desc_count > 1) {
583250661Sdavidcs				c_idx = (comp_idx + desc_count -1) &
584250661Sdavidcs						(NUM_STATUS_DESCRIPTORS-1);
585250661Sdavidcs				sdesc0 = (q80_stat_desc_t *)
586250661Sdavidcs					&hw->sds[sds_idx].sds_ring_base[c_idx];
587250661Sdavidcs
588250661Sdavidcs				if (Q8_STAT_DESC_OPCODE((sdesc0->data[1])) !=
589250661Sdavidcs						Q8_STAT_DESC_OPCODE_CONT) {
590250661Sdavidcs					desc_count = 0;
591250661Sdavidcs					break;
592250661Sdavidcs				}
593250661Sdavidcs			}
594250661Sdavidcs			bzero(&sgc, sizeof(qla_sgl_comp_t));
595250661Sdavidcs
596250661Sdavidcs			sgc.lro.payload_length =
597250661Sdavidcs			Q8_STAT_DESC_TOTAL_LENGTH_SGL_RCV((sdesc->data[0]));
598250661Sdavidcs
599250661Sdavidcs			sgc.lro.rss_hash =
600250661Sdavidcs				Q8_STAT_DESC_RSS_HASH((sdesc->data[0]));
601250661Sdavidcs
602250661Sdavidcs			sgc.lro.num_handles = 1;
603250661Sdavidcs			sgc.lro.handle[0] =
604250661Sdavidcs				Q8_STAT_DESC_HANDLE((sdesc->data[0]));
605250661Sdavidcs
606250661Sdavidcs			if (Q8_SGL_LRO_STAT_TS((sdesc->data[1])))
607250661Sdavidcs				sgc.lro.flags |= Q8_LRO_COMP_TS;
608250661Sdavidcs
609250661Sdavidcs			if (Q8_SGL_LRO_STAT_PUSH_BIT((sdesc->data[1])))
610250661Sdavidcs				sgc.lro.flags |= Q8_LRO_COMP_PUSH_BIT;
611250661Sdavidcs
612250661Sdavidcs			sgc.lro.l2_offset =
613250661Sdavidcs				Q8_SGL_LRO_STAT_L2_OFFSET((sdesc->data[1]));
614250661Sdavidcs			sgc.lro.l4_offset =
615250661Sdavidcs				Q8_SGL_LRO_STAT_L4_OFFSET((sdesc->data[1]));
616250661Sdavidcs
617250661Sdavidcs			if (Q8_STAT_DESC_VLAN((sdesc->data[1]))) {
618250661Sdavidcs				sgc.lro.vlan_tag =
619250661Sdavidcs					Q8_STAT_DESC_VLAN_ID((sdesc->data[1]));
620250661Sdavidcs			}
621250661Sdavidcs
622250661Sdavidcs			QL_ASSERT(ha, (desc_count <= 7) ,\
623250661Sdavidcs				("%s: [sds_idx, data0, data1]="\
624250661Sdavidcs				 "[%d, 0x%llx, 0x%llx]\n",\
625250661Sdavidcs				__func__, sds_idx,\
626250661Sdavidcs				(long long unsigned int)sdesc->data[0],\
627250661Sdavidcs				(long long unsigned int)sdesc->data[1]));
628250661Sdavidcs
629250661Sdavidcs			if (qla_rcv_cont_sds(ha, sds_idx, comp_idx,
630250661Sdavidcs				desc_count, &sgc.lro.handle[1], &nhandles)) {
631250661Sdavidcs				device_printf(dev,
632250661Sdavidcs				"%s: [sds_idx, data0, data1]="\
633250661Sdavidcs				 "[%d, 0x%llx, 0x%llx]\n",\
634250661Sdavidcs				__func__, sds_idx,\
635250661Sdavidcs				(long long unsigned int)sdesc->data[0],\
636250661Sdavidcs				(long long unsigned int)sdesc->data[1]);
637250661Sdavidcs
638250661Sdavidcs				desc_count = 0;
639250661Sdavidcs				break;
640250661Sdavidcs			}
641250661Sdavidcs
642250661Sdavidcs			sgc.lro.num_handles += nhandles;
643250661Sdavidcs
644250661Sdavidcs			if (qla_lro_intr(ha, &sgc.lro, sds_idx)) {
645250661Sdavidcs				device_printf(dev,
646250661Sdavidcs				"%s: [sds_idx, data0, data1]="\
647250661Sdavidcs				 "[%d, 0x%llx, 0x%llx]\n",\
648250661Sdavidcs				__func__, sds_idx,\
649250661Sdavidcs				(long long unsigned int)sdesc->data[0],\
650250661Sdavidcs				(long long unsigned int)sdesc->data[1]);
651250661Sdavidcs				device_printf(dev,
652250661Sdavidcs				"%s: [comp_idx, c_idx, dcount, nhndls]="\
653250661Sdavidcs				 "[%d, %d, %d, %d]\n",\
654250661Sdavidcs				__func__, comp_idx, c_idx, desc_count,
655250661Sdavidcs				sgc.lro.num_handles);
656250661Sdavidcs				if (desc_count > 1) {
657250661Sdavidcs				device_printf(dev,
658250661Sdavidcs				"%s: [sds_idx, data0, data1]="\
659250661Sdavidcs				 "[%d, 0x%llx, 0x%llx]\n",\
660250661Sdavidcs				__func__, sds_idx,\
661250661Sdavidcs				(long long unsigned int)sdesc0->data[0],\
662250661Sdavidcs				(long long unsigned int)sdesc0->data[1]);
663250661Sdavidcs				}
664250661Sdavidcs			}
665250661Sdavidcs
666250661Sdavidcs			break;
667250661Sdavidcs
668250661Sdavidcs		default:
669250661Sdavidcs			device_printf(dev, "%s: default 0x%llx!\n", __func__,
670250661Sdavidcs					(long long unsigned int)sdesc->data[0]);
671250661Sdavidcs			break;
672250661Sdavidcs		}
673250661Sdavidcs
674250661Sdavidcs		if (desc_count == 0)
675250661Sdavidcs			break;
676250661Sdavidcs
677250661Sdavidcs		sds_replenish_threshold += desc_count;
678250661Sdavidcs
679250661Sdavidcs
680250661Sdavidcs		while (desc_count--) {
681250661Sdavidcs			sdesc->data[0] = 0ULL;
682250661Sdavidcs			sdesc->data[1] = 0ULL;
683250661Sdavidcs			comp_idx = (comp_idx + 1) & (NUM_STATUS_DESCRIPTORS-1);
684250661Sdavidcs			sdesc = (q80_stat_desc_t *)
685250661Sdavidcs				&hw->sds[sds_idx].sds_ring_base[comp_idx];
686250661Sdavidcs		}
687250661Sdavidcs
688250661Sdavidcs		if (sds_replenish_threshold > ha->hw.sds_cidx_thres) {
689250661Sdavidcs			sds_replenish_threshold = 0;
690250661Sdavidcs			if (hw->sds[sds_idx].sdsr_next != comp_idx) {
691250661Sdavidcs				QL_UPDATE_SDS_CONSUMER_INDEX(ha, sds_idx,\
692250661Sdavidcs					comp_idx);
693250661Sdavidcs			}
694250661Sdavidcs			hw->sds[sds_idx].sdsr_next = comp_idx;
695250661Sdavidcs		}
696250661Sdavidcs	}
697250661Sdavidcs
698250661Sdavidcs	if (ha->flags.stop_rcv)
699250661Sdavidcs		goto qla_rcv_isr_exit;
700250661Sdavidcs
701250661Sdavidcs	if (hw->sds[sds_idx].sdsr_next != comp_idx) {
702250661Sdavidcs		QL_UPDATE_SDS_CONSUMER_INDEX(ha, sds_idx, comp_idx);
703250661Sdavidcs	}
704250661Sdavidcs	hw->sds[sds_idx].sdsr_next = comp_idx;
705250661Sdavidcs
706250661Sdavidcs	sdesc = (q80_stat_desc_t *)&hw->sds[sds_idx].sds_ring_base[comp_idx];
707250661Sdavidcs	opcode = Q8_STAT_DESC_OPCODE((sdesc->data[1]));
708250661Sdavidcs
709250661Sdavidcs	if (opcode)
710250661Sdavidcs		ret = -1;
711250661Sdavidcs
712250661Sdavidcsqla_rcv_isr_exit:
713250661Sdavidcs	hw->sds[sds_idx].rcv_active = 0;
714250661Sdavidcs
715250661Sdavidcs	return (ret);
716250661Sdavidcs}
717250661Sdavidcs
718250661Sdavidcsvoid
719250661Sdavidcsql_mbx_isr(void *arg)
720250661Sdavidcs{
721250661Sdavidcs	qla_host_t *ha;
722250661Sdavidcs	uint32_t data;
723250661Sdavidcs	uint32_t prev_link_state;
724250661Sdavidcs
725250661Sdavidcs	ha = arg;
726250661Sdavidcs
727250661Sdavidcs	if (ha == NULL) {
728250661Sdavidcs		device_printf(ha->pci_dev, "%s: arg == NULL\n", __func__);
729250661Sdavidcs		return;
730250661Sdavidcs	}
731250661Sdavidcs
732250661Sdavidcs	data = READ_REG32(ha, Q8_FW_MBOX_CNTRL);
733250661Sdavidcs	if ((data & 0x3) != 0x1) {
734250661Sdavidcs		WRITE_REG32(ha, ha->hw.mbx_intr_mask_offset, 0);
735250661Sdavidcs		return;
736250661Sdavidcs	}
737250661Sdavidcs
738250661Sdavidcs	data = READ_REG32(ha, Q8_FW_MBOX0);
739250661Sdavidcs
740250661Sdavidcs	if ((data & 0xF000) != 0x8000)
741250661Sdavidcs		return;
742250661Sdavidcs
743250661Sdavidcs	data = data & 0xFFFF;
744250661Sdavidcs
745250661Sdavidcs	switch (data) {
746250661Sdavidcs
747250661Sdavidcs	case 0x8001:  /* It's an AEN */
748250661Sdavidcs
749250661Sdavidcs		ha->hw.cable_oui = READ_REG32(ha, (Q8_FW_MBOX0 + 4));
750250661Sdavidcs
751250661Sdavidcs		data = READ_REG32(ha, (Q8_FW_MBOX0 + 8));
752250661Sdavidcs		ha->hw.cable_length = data & 0xFFFF;
753250661Sdavidcs
754250661Sdavidcs		data = data >> 16;
755250661Sdavidcs		ha->hw.link_speed = data & 0xFFF;
756250661Sdavidcs
757250661Sdavidcs		data = READ_REG32(ha, (Q8_FW_MBOX0 + 12));
758250661Sdavidcs
759250661Sdavidcs		prev_link_state =  ha->hw.link_up;
760250661Sdavidcs		ha->hw.link_up = (((data & 0xFF) == 0) ? 0 : 1);
761250661Sdavidcs
762250661Sdavidcs		if (prev_link_state !=  ha->hw.link_up) {
763250661Sdavidcs			if (ha->hw.link_up)
764250661Sdavidcs				if_link_state_change(ha->ifp, LINK_STATE_UP);
765250661Sdavidcs			else
766250661Sdavidcs				if_link_state_change(ha->ifp, LINK_STATE_DOWN);
767250661Sdavidcs		}
768250661Sdavidcs
769250661Sdavidcs
770250661Sdavidcs		ha->hw.module_type = ((data >> 8) & 0xFF);
771250661Sdavidcs		ha->hw.flags.fduplex = (((data & 0xFF0000) == 0) ? 0 : 1);
772250661Sdavidcs		ha->hw.flags.autoneg = (((data & 0xFF000000) == 0) ? 0 : 1);
773250661Sdavidcs
774250661Sdavidcs		data = READ_REG32(ha, (Q8_FW_MBOX0 + 16));
775250661Sdavidcs		ha->hw.flags.loopback_mode = data & 0x03;
776250661Sdavidcs
777250661Sdavidcs		ha->hw.link_faults = (data >> 3) & 0xFF;
778250661Sdavidcs
779250661Sdavidcs		WRITE_REG32(ha, Q8_FW_MBOX_CNTRL, 0x0);
780250661Sdavidcs		WRITE_REG32(ha, ha->hw.mbx_intr_mask_offset, 0x0);
781250661Sdavidcs		break;
782250661Sdavidcs
783250661Sdavidcs	default:
784250661Sdavidcs		device_printf(ha->pci_dev, "%s: AEN[0x%08x]\n", __func__, data);
785250661Sdavidcs		WRITE_REG32(ha, Q8_FW_MBOX_CNTRL, 0x0);
786250661Sdavidcs		WRITE_REG32(ha, ha->hw.mbx_intr_mask_offset, 0x0);
787250661Sdavidcs		break;
788250661Sdavidcs	}
789250661Sdavidcs	return;
790250661Sdavidcs}
791250661Sdavidcs
792250661Sdavidcs
793250661Sdavidcsstatic void
794250661Sdavidcsqla_replenish_normal_rx(qla_host_t *ha, qla_sds_t *sdsp, uint32_t r_idx)
795250661Sdavidcs{
796250661Sdavidcs	qla_rx_buf_t *rxb;
797250661Sdavidcs	int count = sdsp->rx_free;
798250661Sdavidcs	uint32_t rx_next;
799250661Sdavidcs	qla_rdesc_t *rdesc;
800250661Sdavidcs
801250661Sdavidcs	/* we can play with this value via a sysctl */
802250661Sdavidcs	uint32_t replenish_thresh = ha->hw.rds_pidx_thres;
803250661Sdavidcs
804250661Sdavidcs	rdesc = &ha->hw.rds[r_idx];
805250661Sdavidcs
806250661Sdavidcs	rx_next = rdesc->rx_next;
807250661Sdavidcs
808250661Sdavidcs	while (count--) {
809250661Sdavidcs		rxb = sdsp->rxb_free;
810250661Sdavidcs
811250661Sdavidcs		if (rxb == NULL)
812250661Sdavidcs			break;
813250661Sdavidcs
814250661Sdavidcs		sdsp->rxb_free = rxb->next;
815250661Sdavidcs		sdsp->rx_free--;
816250661Sdavidcs
817250661Sdavidcs		if (ql_get_mbuf(ha, rxb, NULL) == 0) {
818250661Sdavidcs			qla_set_hw_rcv_desc(ha, r_idx, rdesc->rx_in,
819250661Sdavidcs				rxb->handle,
820250661Sdavidcs				rxb->paddr, (rxb->m_head)->m_pkthdr.len);
821250661Sdavidcs			rdesc->rx_in++;
822250661Sdavidcs			if (rdesc->rx_in == NUM_RX_DESCRIPTORS)
823250661Sdavidcs				rdesc->rx_in = 0;
824250661Sdavidcs			rdesc->rx_next++;
825250661Sdavidcs			if (rdesc->rx_next == NUM_RX_DESCRIPTORS)
826250661Sdavidcs				rdesc->rx_next = 0;
827250661Sdavidcs		} else {
828250661Sdavidcs			device_printf(ha->pci_dev,
829250661Sdavidcs				"%s: ql_get_mbuf [0,(%d),(%d)] failed\n",
830250661Sdavidcs				__func__, rdesc->rx_in, rxb->handle);
831250661Sdavidcs
832250661Sdavidcs			rxb->m_head = NULL;
833250661Sdavidcs			rxb->next = sdsp->rxb_free;
834250661Sdavidcs			sdsp->rxb_free = rxb;
835250661Sdavidcs			sdsp->rx_free++;
836250661Sdavidcs
837250661Sdavidcs			break;
838250661Sdavidcs		}
839250661Sdavidcs		if (replenish_thresh-- == 0) {
840250661Sdavidcs			QL_UPDATE_RDS_PRODUCER_INDEX(ha, rdesc->prod_std,
841250661Sdavidcs				rdesc->rx_next);
842250661Sdavidcs			rx_next = rdesc->rx_next;
843250661Sdavidcs			replenish_thresh = ha->hw.rds_pidx_thres;
844250661Sdavidcs		}
845250661Sdavidcs	}
846250661Sdavidcs
847250661Sdavidcs	if (rx_next != rdesc->rx_next) {
848250661Sdavidcs		QL_UPDATE_RDS_PRODUCER_INDEX(ha, rdesc->prod_std,
849250661Sdavidcs			rdesc->rx_next);
850250661Sdavidcs	}
851250661Sdavidcs}
852250661Sdavidcs
853250661Sdavidcsvoid
854250661Sdavidcsql_isr(void *arg)
855250661Sdavidcs{
856250661Sdavidcs	qla_ivec_t *ivec = arg;
857250661Sdavidcs	qla_host_t *ha ;
858250661Sdavidcs	int idx;
859250661Sdavidcs	qla_hw_t *hw;
860250661Sdavidcs	struct ifnet *ifp;
861250661Sdavidcs	uint32_t ret = 0;
862250661Sdavidcs
863250661Sdavidcs	ha = ivec->ha;
864250661Sdavidcs	hw = &ha->hw;
865250661Sdavidcs	ifp = ha->ifp;
866250661Sdavidcs
867250661Sdavidcs	if ((idx = ivec->sds_idx) >= ha->hw.num_sds_rings)
868250661Sdavidcs		return;
869250661Sdavidcs
870250661Sdavidcs	if (idx == 0)
871250661Sdavidcs		taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
872250661Sdavidcs
873251605Sdavidcs	ret = qla_rcv_isr(ha, idx, -1);
874250661Sdavidcs
875250661Sdavidcs	if (idx == 0)
876250661Sdavidcs		taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
877250661Sdavidcs
878250661Sdavidcs	if (!ha->flags.stop_rcv) {
879250661Sdavidcs		QL_ENABLE_INTERRUPTS(ha, idx);
880250661Sdavidcs	}
881250661Sdavidcs	return;
882250661Sdavidcs}
883250661Sdavidcs
884