xref: /freebsd/sys/dev/qlxgbe/ql_isr.c (revision a98ff317388a00b992f1bf8404dee596f9383f5e)
1 /*
2  * Copyright (c) 2013-2014 Qlogic Corporation
3  * All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions
7  *  are met:
8  *
9  *  1. Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  *  2. Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  *  POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 /*
29  * File: ql_isr.c
30  * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656.
31  */
32 
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35 
36 
37 #include "ql_os.h"
38 #include "ql_hw.h"
39 #include "ql_def.h"
40 #include "ql_inline.h"
41 #include "ql_ver.h"
42 #include "ql_glbl.h"
43 #include "ql_dbg.h"
44 
45 static void qla_replenish_normal_rx(qla_host_t *ha, qla_sds_t *sdsp,
46 		uint32_t r_idx);
47 
48 static void
49 qla_rcv_error(qla_host_t *ha)
50 {
51 	ha->flags.stop_rcv = 1;
52 	ha->qla_initiate_recovery = 1;
53 }
54 
55 
56 /*
57  * Name: qla_rx_intr
58  * Function: Handles normal ethernet frames received
59  */
60 static void
61 qla_rx_intr(qla_host_t *ha, qla_sgl_rcv_t *sgc, uint32_t sds_idx)
62 {
63 	qla_rx_buf_t		*rxb;
64 	struct mbuf		*mp = NULL, *mpf = NULL, *mpl = NULL;
65 	struct ifnet		*ifp = ha->ifp;
66 	qla_sds_t		*sdsp;
67 	struct ether_vlan_header *eh;
68 	uint32_t		i, rem_len = 0;
69 	uint32_t		r_idx = 0;
70 	qla_rx_ring_t		*rx_ring;
71 
72 	if (ha->hw.num_rds_rings > 1)
73 		r_idx = sds_idx;
74 
75 	ha->hw.rds[r_idx].count++;
76 
77 	sdsp = &ha->hw.sds[sds_idx];
78 	rx_ring = &ha->rx_ring[r_idx];
79 
80 	for (i = 0; i < sgc->num_handles; i++) {
81 		rxb = &rx_ring->rx_buf[sgc->handle[i] & 0x7FFF];
82 
83 		QL_ASSERT(ha, (rxb != NULL),
84 			("%s: [sds_idx]=[%d] rxb != NULL\n", __func__,\
85 			sds_idx));
86 
87 		if ((rxb == NULL) || QL_ERR_INJECT(ha, INJCT_RX_RXB_INVAL)) {
88 			/* log the error */
89 			device_printf(ha->pci_dev,
90 				"%s invalid rxb[%d, %d, 0x%04x]\n",
91 				__func__, sds_idx, i, sgc->handle[i]);
92 			qla_rcv_error(ha);
93 			return;
94 		}
95 
96 		mp = rxb->m_head;
97 		if (i == 0)
98 			mpf = mp;
99 
100 		QL_ASSERT(ha, (mp != NULL),
101 			("%s: [sds_idx]=[%d] mp != NULL\n", __func__,\
102 			sds_idx));
103 
104 		bus_dmamap_sync(ha->rx_tag, rxb->map, BUS_DMASYNC_POSTREAD);
105 
106 		rxb->m_head = NULL;
107 		rxb->next = sdsp->rxb_free;
108 		sdsp->rxb_free = rxb;
109 		sdsp->rx_free++;
110 
111 		if ((mp == NULL) || QL_ERR_INJECT(ha, INJCT_RX_MP_NULL)) {
112 			/* log the error */
113 			device_printf(ha->pci_dev,
114 				"%s mp  == NULL [%d, %d, 0x%04x]\n",
115 				__func__, sds_idx, i, sgc->handle[i]);
116 			qla_rcv_error(ha);
117 			return;
118 		}
119 
120 		if (i == 0) {
121 			mpl = mpf = mp;
122 			mp->m_flags |= M_PKTHDR;
123 			mp->m_pkthdr.len = sgc->pkt_length;
124 			mp->m_pkthdr.rcvif = ifp;
125 			rem_len = mp->m_pkthdr.len;
126 		} else {
127 			mp->m_flags &= ~M_PKTHDR;
128 			mpl->m_next = mp;
129 			mpl = mp;
130 			rem_len = rem_len - mp->m_len;
131 		}
132 	}
133 
134 	mpl->m_len = rem_len;
135 
136 	eh = mtod(mpf, struct ether_vlan_header *);
137 
138 	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
139 		uint32_t *data = (uint32_t *)eh;
140 
141 		mpf->m_pkthdr.ether_vtag = ntohs(eh->evl_tag);
142 		mpf->m_flags |= M_VLANTAG;
143 
144 		*(data + 3) = *(data + 2);
145 		*(data + 2) = *(data + 1);
146 		*(data + 1) = *data;
147 
148 		m_adj(mpf, ETHER_VLAN_ENCAP_LEN);
149 	}
150 
151 	if (sgc->chksum_status == Q8_STAT_DESC_STATUS_CHKSUM_OK) {
152 		mpf->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID |
153 			CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
154 		mpf->m_pkthdr.csum_data = 0xFFFF;
155 	} else {
156 		mpf->m_pkthdr.csum_flags = 0;
157 	}
158 
159 	ifp->if_ipackets++;
160 
161 	mpf->m_pkthdr.flowid = sgc->rss_hash;
162 	mpf->m_flags |= M_FLOWID;
163 
164 	(*ifp->if_input)(ifp, mpf);
165 
166 	if (sdsp->rx_free > ha->std_replenish)
167 		qla_replenish_normal_rx(ha, sdsp, r_idx);
168 
169 	return;
170 }
171 
172 #define QLA_TCP_HDR_SIZE        20
173 #define QLA_TCP_TS_OPTION_SIZE  12
174 
175 /*
176  * Name: qla_lro_intr
177  * Function: Handles normal ethernet frames received
178  */
179 static int
180 qla_lro_intr(qla_host_t *ha, qla_sgl_lro_t *sgc, uint32_t sds_idx)
181 {
182 	qla_rx_buf_t *rxb;
183 	struct mbuf *mp = NULL, *mpf = NULL, *mpl = NULL;
184 	struct ifnet *ifp = ha->ifp;
185 	qla_sds_t *sdsp;
186 	struct ether_vlan_header *eh;
187 	uint32_t i, rem_len = 0, pkt_length, iplen;
188 	struct tcphdr *th;
189 	struct ip *ip = NULL;
190 	struct ip6_hdr *ip6 = NULL;
191 	uint16_t etype;
192 	uint32_t r_idx = 0;
193 	qla_rx_ring_t *rx_ring;
194 
195 	if (ha->hw.num_rds_rings > 1)
196 		r_idx = sds_idx;
197 
198 	ha->hw.rds[r_idx].count++;
199 
200 	rx_ring = &ha->rx_ring[r_idx];
201 
202 	ha->lro_pkt_count++;
203 
204 	sdsp = &ha->hw.sds[sds_idx];
205 
206 	pkt_length = sgc->payload_length + sgc->l4_offset;
207 
208 	if (sgc->flags & Q8_LRO_COMP_TS) {
209 		pkt_length += QLA_TCP_HDR_SIZE + QLA_TCP_TS_OPTION_SIZE;
210 	} else {
211 		pkt_length += QLA_TCP_HDR_SIZE;
212 	}
213 	ha->lro_bytes += pkt_length;
214 
215 	for (i = 0; i < sgc->num_handles; i++) {
216 		rxb = &rx_ring->rx_buf[sgc->handle[i] & 0x7FFF];
217 
218 		QL_ASSERT(ha, (rxb != NULL),
219 			("%s: [sds_idx]=[%d] rxb != NULL\n", __func__,\
220 			sds_idx));
221 
222 		if ((rxb == NULL) || QL_ERR_INJECT(ha, INJCT_LRO_RXB_INVAL)) {
223 			/* log the error */
224 			device_printf(ha->pci_dev,
225 				"%s invalid rxb[%d, %d, 0x%04x]\n",
226 				__func__, sds_idx, i, sgc->handle[i]);
227 			qla_rcv_error(ha);
228 			return (0);
229 		}
230 
231 		mp = rxb->m_head;
232 		if (i == 0)
233 			mpf = mp;
234 
235 		QL_ASSERT(ha, (mp != NULL),
236 			("%s: [sds_idx]=[%d] mp != NULL\n", __func__,\
237 			sds_idx));
238 
239 		bus_dmamap_sync(ha->rx_tag, rxb->map, BUS_DMASYNC_POSTREAD);
240 
241 		rxb->m_head = NULL;
242 		rxb->next = sdsp->rxb_free;
243 		sdsp->rxb_free = rxb;
244 		sdsp->rx_free++;
245 
246 		if ((mp == NULL) || QL_ERR_INJECT(ha, INJCT_LRO_MP_NULL)) {
247 			/* log the error */
248 			device_printf(ha->pci_dev,
249 				"%s mp  == NULL [%d, %d, 0x%04x]\n",
250 				__func__, sds_idx, i, sgc->handle[i]);
251 			qla_rcv_error(ha);
252 			return (0);
253 		}
254 
255 		if (i == 0) {
256 			mpl = mpf = mp;
257 			mp->m_flags |= M_PKTHDR;
258 			mp->m_pkthdr.len = pkt_length;
259 			mp->m_pkthdr.rcvif = ifp;
260 			rem_len = mp->m_pkthdr.len;
261 		} else {
262 			mp->m_flags &= ~M_PKTHDR;
263 			mpl->m_next = mp;
264 			mpl = mp;
265 			rem_len = rem_len - mp->m_len;
266 		}
267 	}
268 
269 	mpl->m_len = rem_len;
270 
271 	th = (struct tcphdr *)(mpf->m_data + sgc->l4_offset);
272 
273 	if (sgc->flags & Q8_LRO_COMP_PUSH_BIT)
274 		th->th_flags |= TH_PUSH;
275 
276 	m_adj(mpf, sgc->l2_offset);
277 
278 	eh = mtod(mpf, struct ether_vlan_header *);
279 
280 	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
281 		uint32_t *data = (uint32_t *)eh;
282 
283 		mpf->m_pkthdr.ether_vtag = ntohs(eh->evl_tag);
284 		mpf->m_flags |= M_VLANTAG;
285 
286 		*(data + 3) = *(data + 2);
287 		*(data + 2) = *(data + 1);
288 		*(data + 1) = *data;
289 
290 		m_adj(mpf, ETHER_VLAN_ENCAP_LEN);
291 
292 		etype = ntohs(eh->evl_proto);
293 	} else {
294 		etype = ntohs(eh->evl_encap_proto);
295 	}
296 
297 	if (etype == ETHERTYPE_IP) {
298 		ip = (struct ip *)(mpf->m_data + ETHER_HDR_LEN);
299 
300 		iplen = (ip->ip_hl << 2) + (th->th_off << 2) +
301 				sgc->payload_length;
302 
303                 ip->ip_len = htons(iplen);
304 
305 		ha->ipv4_lro++;
306 	} else if (etype == ETHERTYPE_IPV6) {
307 		ip6 = (struct ip6_hdr *)(mpf->m_data + ETHER_HDR_LEN);
308 
309 		iplen = (th->th_off << 2) + sgc->payload_length;
310 
311 		ip6->ip6_plen = htons(iplen);
312 
313 		ha->ipv6_lro++;
314 	} else {
315 		m_freem(mpf);
316 
317 		if (sdsp->rx_free > ha->std_replenish)
318 			qla_replenish_normal_rx(ha, sdsp, r_idx);
319 		return 0;
320 	}
321 
322 	mpf->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID |
323 					CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
324 	mpf->m_pkthdr.csum_data = 0xFFFF;
325 
326 	mpf->m_pkthdr.flowid = sgc->rss_hash;
327 	mpf->m_flags |= M_FLOWID;
328 
329 	ifp->if_ipackets++;
330 
331 	(*ifp->if_input)(ifp, mpf);
332 
333 	if (sdsp->rx_free > ha->std_replenish)
334 		qla_replenish_normal_rx(ha, sdsp, r_idx);
335 
336 	return (0);
337 }
338 
339 static int
340 qla_rcv_cont_sds(qla_host_t *ha, uint32_t sds_idx, uint32_t comp_idx,
341 	uint32_t dcount, uint16_t *handle, uint16_t *nhandles)
342 {
343 	uint32_t i;
344 	uint16_t num_handles;
345 	q80_stat_desc_t *sdesc;
346 	uint32_t opcode;
347 
348 	*nhandles = 0;
349 	dcount--;
350 
351 	for (i = 0; i < dcount; i++) {
352 		comp_idx = (comp_idx + 1) & (NUM_STATUS_DESCRIPTORS-1);
353 		sdesc = (q80_stat_desc_t *)
354 				&ha->hw.sds[sds_idx].sds_ring_base[comp_idx];
355 
356 		opcode = Q8_STAT_DESC_OPCODE((sdesc->data[1]));
357 
358 		if (!opcode) {
359 			device_printf(ha->pci_dev, "%s: opcode=0 %p %p\n",
360 				__func__, (void *)sdesc->data[0],
361 				(void *)sdesc->data[1]);
362 			return -1;
363 		}
364 
365 		num_handles = Q8_SGL_STAT_DESC_NUM_HANDLES((sdesc->data[1]));
366 		if (!num_handles) {
367 			device_printf(ha->pci_dev, "%s: opcode=0 %p %p\n",
368 				__func__, (void *)sdesc->data[0],
369 				(void *)sdesc->data[1]);
370 			return -1;
371 		}
372 
373 		if (QL_ERR_INJECT(ha, INJCT_NUM_HNDLE_INVALID))
374 			num_handles = -1;
375 
376 		switch (num_handles) {
377 
378 		case 1:
379 			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
380 			break;
381 
382 		case 2:
383 			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
384 			*handle++ = Q8_SGL_STAT_DESC_HANDLE2((sdesc->data[0]));
385 			break;
386 
387 		case 3:
388 			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
389 			*handle++ = Q8_SGL_STAT_DESC_HANDLE2((sdesc->data[0]));
390 			*handle++ = Q8_SGL_STAT_DESC_HANDLE3((sdesc->data[0]));
391 			break;
392 
393 		case 4:
394 			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
395 			*handle++ = Q8_SGL_STAT_DESC_HANDLE2((sdesc->data[0]));
396 			*handle++ = Q8_SGL_STAT_DESC_HANDLE3((sdesc->data[0]));
397 			*handle++ = Q8_SGL_STAT_DESC_HANDLE4((sdesc->data[0]));
398 			break;
399 
400 		case 5:
401 			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
402 			*handle++ = Q8_SGL_STAT_DESC_HANDLE2((sdesc->data[0]));
403 			*handle++ = Q8_SGL_STAT_DESC_HANDLE3((sdesc->data[0]));
404 			*handle++ = Q8_SGL_STAT_DESC_HANDLE4((sdesc->data[0]));
405 			*handle++ = Q8_SGL_STAT_DESC_HANDLE5((sdesc->data[1]));
406 			break;
407 
408 		case 6:
409 			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
410 			*handle++ = Q8_SGL_STAT_DESC_HANDLE2((sdesc->data[0]));
411 			*handle++ = Q8_SGL_STAT_DESC_HANDLE3((sdesc->data[0]));
412 			*handle++ = Q8_SGL_STAT_DESC_HANDLE4((sdesc->data[0]));
413 			*handle++ = Q8_SGL_STAT_DESC_HANDLE5((sdesc->data[1]));
414 			*handle++ = Q8_SGL_STAT_DESC_HANDLE6((sdesc->data[1]));
415 			break;
416 
417 		case 7:
418 			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
419 			*handle++ = Q8_SGL_STAT_DESC_HANDLE2((sdesc->data[0]));
420 			*handle++ = Q8_SGL_STAT_DESC_HANDLE3((sdesc->data[0]));
421 			*handle++ = Q8_SGL_STAT_DESC_HANDLE4((sdesc->data[0]));
422 			*handle++ = Q8_SGL_STAT_DESC_HANDLE5((sdesc->data[1]));
423 			*handle++ = Q8_SGL_STAT_DESC_HANDLE6((sdesc->data[1]));
424 			*handle++ = Q8_SGL_STAT_DESC_HANDLE7((sdesc->data[1]));
425 			break;
426 
427 		default:
428 			device_printf(ha->pci_dev,
429 				"%s: invalid num handles %p %p\n",
430 				__func__, (void *)sdesc->data[0],
431 				(void *)sdesc->data[1]);
432 
433 			QL_ASSERT(ha, (0),\
434 			("%s: %s [nh, sds, d0, d1]=[%d, %d, %p, %p]\n",
435 			__func__, "invalid num handles", sds_idx, num_handles,
436 			(void *)sdesc->data[0],(void *)sdesc->data[1]));
437 
438 			qla_rcv_error(ha);
439 			return 0;
440 		}
441 		*nhandles = *nhandles + num_handles;
442 	}
443 	return 0;
444 }
445 
446 /*
447  * Name: qla_rcv_isr
448  * Function: Main Interrupt Service Routine
449  */
450 static uint32_t
451 qla_rcv_isr(qla_host_t *ha, uint32_t sds_idx, uint32_t count)
452 {
453 	device_t dev;
454 	qla_hw_t *hw;
455 	uint32_t comp_idx, c_idx = 0, desc_count = 0, opcode;
456 	volatile q80_stat_desc_t *sdesc, *sdesc0 = NULL;
457 	uint32_t ret = 0;
458 	qla_sgl_comp_t sgc;
459 	uint16_t nhandles;
460 	uint32_t sds_replenish_threshold = 0;
461 
462 	dev = ha->pci_dev;
463 	hw = &ha->hw;
464 
465 	hw->sds[sds_idx].rcv_active = 1;
466 	if (ha->flags.stop_rcv) {
467 		hw->sds[sds_idx].rcv_active = 0;
468 		return 0;
469 	}
470 
471 	QL_DPRINT2(ha, (dev, "%s: [%d]enter\n", __func__, sds_idx));
472 
473 	/*
474 	 * receive interrupts
475 	 */
476 	comp_idx = hw->sds[sds_idx].sdsr_next;
477 
478 	while (count-- && !ha->flags.stop_rcv) {
479 
480 		sdesc = (q80_stat_desc_t *)
481 				&hw->sds[sds_idx].sds_ring_base[comp_idx];
482 
483 		opcode = Q8_STAT_DESC_OPCODE((sdesc->data[1]));
484 
485 		if (!opcode)
486 			break;
487 
488 		hw->sds[sds_idx].intr_count++;
489 		switch (opcode) {
490 
491 		case Q8_STAT_DESC_OPCODE_RCV_PKT:
492 
493 			desc_count = 1;
494 
495 			bzero(&sgc, sizeof(qla_sgl_comp_t));
496 
497 			sgc.rcv.pkt_length =
498 				Q8_STAT_DESC_TOTAL_LENGTH((sdesc->data[0]));
499 			sgc.rcv.num_handles = 1;
500 			sgc.rcv.handle[0] =
501 				Q8_STAT_DESC_HANDLE((sdesc->data[0]));
502 			sgc.rcv.chksum_status =
503 				Q8_STAT_DESC_STATUS((sdesc->data[1]));
504 
505 			sgc.rcv.rss_hash =
506 				Q8_STAT_DESC_RSS_HASH((sdesc->data[0]));
507 
508 			if (Q8_STAT_DESC_VLAN((sdesc->data[1]))) {
509 				sgc.rcv.vlan_tag =
510 					Q8_STAT_DESC_VLAN_ID((sdesc->data[1]));
511 			}
512 			qla_rx_intr(ha, &sgc.rcv, sds_idx);
513 			break;
514 
515 		case Q8_STAT_DESC_OPCODE_SGL_RCV:
516 
517 			desc_count =
518 				Q8_STAT_DESC_COUNT_SGL_RCV((sdesc->data[1]));
519 
520 			if (desc_count > 1) {
521 				c_idx = (comp_idx + desc_count -1) &
522 						(NUM_STATUS_DESCRIPTORS-1);
523 				sdesc0 = (q80_stat_desc_t *)
524 					&hw->sds[sds_idx].sds_ring_base[c_idx];
525 
526 				if (Q8_STAT_DESC_OPCODE((sdesc0->data[1])) !=
527 						Q8_STAT_DESC_OPCODE_CONT) {
528 					desc_count = 0;
529 					break;
530 				}
531 			}
532 
533 			bzero(&sgc, sizeof(qla_sgl_comp_t));
534 
535 			sgc.rcv.pkt_length =
536 				Q8_STAT_DESC_TOTAL_LENGTH_SGL_RCV(\
537 					(sdesc->data[0]));
538 			sgc.rcv.chksum_status =
539 				Q8_STAT_DESC_STATUS((sdesc->data[1]));
540 
541 			sgc.rcv.rss_hash =
542 				Q8_STAT_DESC_RSS_HASH((sdesc->data[0]));
543 
544 			if (Q8_STAT_DESC_VLAN((sdesc->data[1]))) {
545 				sgc.rcv.vlan_tag =
546 					Q8_STAT_DESC_VLAN_ID((sdesc->data[1]));
547 			}
548 
549 			QL_ASSERT(ha, (desc_count <= 2) ,\
550 				("%s: [sds_idx, data0, data1]="\
551 				"%d, %p, %p]\n", __func__, sds_idx,\
552 				(void *)sdesc->data[0],\
553 				(void *)sdesc->data[1]));
554 
555 			sgc.rcv.num_handles = 1;
556 			sgc.rcv.handle[0] =
557 				Q8_STAT_DESC_HANDLE((sdesc->data[0]));
558 
559 			if (qla_rcv_cont_sds(ha, sds_idx, comp_idx, desc_count,
560 				&sgc.rcv.handle[1], &nhandles)) {
561 				device_printf(dev,
562 					"%s: [sds_idx, dcount, data0, data1]="
563 					 "[%d, %d, 0x%llx, 0x%llx]\n",
564 					__func__, sds_idx, desc_count,
565 					(long long unsigned int)sdesc->data[0],
566 					(long long unsigned int)sdesc->data[1]);
567 				desc_count = 0;
568 				break;
569 			}
570 
571 			sgc.rcv.num_handles += nhandles;
572 
573 			qla_rx_intr(ha, &sgc.rcv, sds_idx);
574 
575 			break;
576 
577 		case Q8_STAT_DESC_OPCODE_SGL_LRO:
578 
579 			desc_count =
580 				Q8_STAT_DESC_COUNT_SGL_LRO((sdesc->data[1]));
581 
582 			if (desc_count > 1) {
583 				c_idx = (comp_idx + desc_count -1) &
584 						(NUM_STATUS_DESCRIPTORS-1);
585 				sdesc0 = (q80_stat_desc_t *)
586 					&hw->sds[sds_idx].sds_ring_base[c_idx];
587 
588 				if (Q8_STAT_DESC_OPCODE((sdesc0->data[1])) !=
589 						Q8_STAT_DESC_OPCODE_CONT) {
590 					desc_count = 0;
591 					break;
592 				}
593 			}
594 			bzero(&sgc, sizeof(qla_sgl_comp_t));
595 
596 			sgc.lro.payload_length =
597 			Q8_STAT_DESC_TOTAL_LENGTH_SGL_RCV((sdesc->data[0]));
598 
599 			sgc.lro.rss_hash =
600 				Q8_STAT_DESC_RSS_HASH((sdesc->data[0]));
601 
602 			sgc.lro.num_handles = 1;
603 			sgc.lro.handle[0] =
604 				Q8_STAT_DESC_HANDLE((sdesc->data[0]));
605 
606 			if (Q8_SGL_LRO_STAT_TS((sdesc->data[1])))
607 				sgc.lro.flags |= Q8_LRO_COMP_TS;
608 
609 			if (Q8_SGL_LRO_STAT_PUSH_BIT((sdesc->data[1])))
610 				sgc.lro.flags |= Q8_LRO_COMP_PUSH_BIT;
611 
612 			sgc.lro.l2_offset =
613 				Q8_SGL_LRO_STAT_L2_OFFSET((sdesc->data[1]));
614 			sgc.lro.l4_offset =
615 				Q8_SGL_LRO_STAT_L4_OFFSET((sdesc->data[1]));
616 
617 			if (Q8_STAT_DESC_VLAN((sdesc->data[1]))) {
618 				sgc.lro.vlan_tag =
619 					Q8_STAT_DESC_VLAN_ID((sdesc->data[1]));
620 			}
621 
622 			QL_ASSERT(ha, (desc_count <= 7) ,\
623 				("%s: [sds_idx, data0, data1]="\
624 				 "[%d, 0x%llx, 0x%llx]\n",\
625 				__func__, sds_idx,\
626 				(long long unsigned int)sdesc->data[0],\
627 				(long long unsigned int)sdesc->data[1]));
628 
629 			if (qla_rcv_cont_sds(ha, sds_idx, comp_idx,
630 				desc_count, &sgc.lro.handle[1], &nhandles)) {
631 				device_printf(dev,
632 				"%s: [sds_idx, data0, data1]="\
633 				 "[%d, 0x%llx, 0x%llx]\n",\
634 				__func__, sds_idx,\
635 				(long long unsigned int)sdesc->data[0],\
636 				(long long unsigned int)sdesc->data[1]);
637 
638 				desc_count = 0;
639 				break;
640 			}
641 
642 			sgc.lro.num_handles += nhandles;
643 
644 			if (qla_lro_intr(ha, &sgc.lro, sds_idx)) {
645 				device_printf(dev,
646 				"%s: [sds_idx, data0, data1]="\
647 				 "[%d, 0x%llx, 0x%llx]\n",\
648 				__func__, sds_idx,\
649 				(long long unsigned int)sdesc->data[0],\
650 				(long long unsigned int)sdesc->data[1]);
651 				device_printf(dev,
652 				"%s: [comp_idx, c_idx, dcount, nhndls]="\
653 				 "[%d, %d, %d, %d]\n",\
654 				__func__, comp_idx, c_idx, desc_count,
655 				sgc.lro.num_handles);
656 				if (desc_count > 1) {
657 				device_printf(dev,
658 				"%s: [sds_idx, data0, data1]="\
659 				 "[%d, 0x%llx, 0x%llx]\n",\
660 				__func__, sds_idx,\
661 				(long long unsigned int)sdesc0->data[0],\
662 				(long long unsigned int)sdesc0->data[1]);
663 				}
664 			}
665 
666 			break;
667 
668 		default:
669 			device_printf(dev, "%s: default 0x%llx!\n", __func__,
670 					(long long unsigned int)sdesc->data[0]);
671 			break;
672 		}
673 
674 		if (desc_count == 0)
675 			break;
676 
677 		sds_replenish_threshold += desc_count;
678 
679 
680 		while (desc_count--) {
681 			sdesc->data[0] = 0ULL;
682 			sdesc->data[1] = 0ULL;
683 			comp_idx = (comp_idx + 1) & (NUM_STATUS_DESCRIPTORS-1);
684 			sdesc = (q80_stat_desc_t *)
685 				&hw->sds[sds_idx].sds_ring_base[comp_idx];
686 		}
687 
688 		if (sds_replenish_threshold > ha->hw.sds_cidx_thres) {
689 			sds_replenish_threshold = 0;
690 			if (hw->sds[sds_idx].sdsr_next != comp_idx) {
691 				QL_UPDATE_SDS_CONSUMER_INDEX(ha, sds_idx,\
692 					comp_idx);
693 			}
694 			hw->sds[sds_idx].sdsr_next = comp_idx;
695 		}
696 	}
697 
698 	if (ha->flags.stop_rcv)
699 		goto qla_rcv_isr_exit;
700 
701 	if (hw->sds[sds_idx].sdsr_next != comp_idx) {
702 		QL_UPDATE_SDS_CONSUMER_INDEX(ha, sds_idx, comp_idx);
703 	}
704 	hw->sds[sds_idx].sdsr_next = comp_idx;
705 
706 	sdesc = (q80_stat_desc_t *)&hw->sds[sds_idx].sds_ring_base[comp_idx];
707 	opcode = Q8_STAT_DESC_OPCODE((sdesc->data[1]));
708 
709 	if (opcode)
710 		ret = -1;
711 
712 qla_rcv_isr_exit:
713 	hw->sds[sds_idx].rcv_active = 0;
714 
715 	return (ret);
716 }
717 
718 void
719 ql_mbx_isr(void *arg)
720 {
721 	qla_host_t *ha;
722 	uint32_t data;
723 	uint32_t prev_link_state;
724 
725 	ha = arg;
726 
727 	if (ha == NULL) {
728 		device_printf(ha->pci_dev, "%s: arg == NULL\n", __func__);
729 		return;
730 	}
731 
732 	data = READ_REG32(ha, Q8_FW_MBOX_CNTRL);
733 	if ((data & 0x3) != 0x1) {
734 		WRITE_REG32(ha, ha->hw.mbx_intr_mask_offset, 0);
735 		return;
736 	}
737 
738 	data = READ_REG32(ha, Q8_FW_MBOX0);
739 
740 	if ((data & 0xF000) != 0x8000)
741 		return;
742 
743 	data = data & 0xFFFF;
744 
745 	switch (data) {
746 
747 	case 0x8001:  /* It's an AEN */
748 
749 		ha->hw.cable_oui = READ_REG32(ha, (Q8_FW_MBOX0 + 4));
750 
751 		data = READ_REG32(ha, (Q8_FW_MBOX0 + 8));
752 		ha->hw.cable_length = data & 0xFFFF;
753 
754 		data = data >> 16;
755 		ha->hw.link_speed = data & 0xFFF;
756 
757 		data = READ_REG32(ha, (Q8_FW_MBOX0 + 12));
758 
759 		prev_link_state =  ha->hw.link_up;
760 		ha->hw.link_up = (((data & 0xFF) == 0) ? 0 : 1);
761 
762 		if (prev_link_state !=  ha->hw.link_up) {
763 			if (ha->hw.link_up)
764 				if_link_state_change(ha->ifp, LINK_STATE_UP);
765 			else
766 				if_link_state_change(ha->ifp, LINK_STATE_DOWN);
767 		}
768 
769 
770 		ha->hw.module_type = ((data >> 8) & 0xFF);
771 		ha->hw.flags.fduplex = (((data & 0xFF0000) == 0) ? 0 : 1);
772 		ha->hw.flags.autoneg = (((data & 0xFF000000) == 0) ? 0 : 1);
773 
774 		data = READ_REG32(ha, (Q8_FW_MBOX0 + 16));
775 		ha->hw.flags.loopback_mode = data & 0x03;
776 
777 		ha->hw.link_faults = (data >> 3) & 0xFF;
778 
779 		WRITE_REG32(ha, Q8_FW_MBOX_CNTRL, 0x0);
780 		WRITE_REG32(ha, ha->hw.mbx_intr_mask_offset, 0x0);
781 		break;
782 
783 	default:
784 		device_printf(ha->pci_dev, "%s: AEN[0x%08x]\n", __func__, data);
785 		WRITE_REG32(ha, Q8_FW_MBOX_CNTRL, 0x0);
786 		WRITE_REG32(ha, ha->hw.mbx_intr_mask_offset, 0x0);
787 		break;
788 	}
789 	return;
790 }
791 
792 
793 static void
794 qla_replenish_normal_rx(qla_host_t *ha, qla_sds_t *sdsp, uint32_t r_idx)
795 {
796 	qla_rx_buf_t *rxb;
797 	int count = sdsp->rx_free;
798 	uint32_t rx_next;
799 	qla_rdesc_t *rdesc;
800 
801 	/* we can play with this value via a sysctl */
802 	uint32_t replenish_thresh = ha->hw.rds_pidx_thres;
803 
804 	rdesc = &ha->hw.rds[r_idx];
805 
806 	rx_next = rdesc->rx_next;
807 
808 	while (count--) {
809 		rxb = sdsp->rxb_free;
810 
811 		if (rxb == NULL)
812 			break;
813 
814 		sdsp->rxb_free = rxb->next;
815 		sdsp->rx_free--;
816 
817 		if (ql_get_mbuf(ha, rxb, NULL) == 0) {
818 			qla_set_hw_rcv_desc(ha, r_idx, rdesc->rx_in,
819 				rxb->handle,
820 				rxb->paddr, (rxb->m_head)->m_pkthdr.len);
821 			rdesc->rx_in++;
822 			if (rdesc->rx_in == NUM_RX_DESCRIPTORS)
823 				rdesc->rx_in = 0;
824 			rdesc->rx_next++;
825 			if (rdesc->rx_next == NUM_RX_DESCRIPTORS)
826 				rdesc->rx_next = 0;
827 		} else {
828 			device_printf(ha->pci_dev,
829 				"%s: ql_get_mbuf [0,(%d),(%d)] failed\n",
830 				__func__, rdesc->rx_in, rxb->handle);
831 
832 			rxb->m_head = NULL;
833 			rxb->next = sdsp->rxb_free;
834 			sdsp->rxb_free = rxb;
835 			sdsp->rx_free++;
836 
837 			break;
838 		}
839 		if (replenish_thresh-- == 0) {
840 			QL_UPDATE_RDS_PRODUCER_INDEX(ha, rdesc->prod_std,
841 				rdesc->rx_next);
842 			rx_next = rdesc->rx_next;
843 			replenish_thresh = ha->hw.rds_pidx_thres;
844 		}
845 	}
846 
847 	if (rx_next != rdesc->rx_next) {
848 		QL_UPDATE_RDS_PRODUCER_INDEX(ha, rdesc->prod_std,
849 			rdesc->rx_next);
850 	}
851 }
852 
853 void
854 ql_isr(void *arg)
855 {
856 	qla_ivec_t *ivec = arg;
857 	qla_host_t *ha ;
858 	int idx;
859 	qla_hw_t *hw;
860 	struct ifnet *ifp;
861 	uint32_t ret = 0;
862 
863 	ha = ivec->ha;
864 	hw = &ha->hw;
865 	ifp = ha->ifp;
866 
867 	if ((idx = ivec->sds_idx) >= ha->hw.num_sds_rings)
868 		return;
869 
870 	if (idx == 0)
871 		taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
872 
873 	ret = qla_rcv_isr(ha, idx, -1);
874 
875 	if (idx == 0)
876 		taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
877 
878 	if (!ha->flags.stop_rcv) {
879 		QL_ENABLE_INTERRUPTS(ha, idx);
880 	}
881 	return;
882 }
883 
884