xref: /freebsd/sys/dev/qlxgbe/ql_isr.c (revision cdebaff820b2a4915a16cedfd511823d78aab171)
1 /*
2  * Copyright (c) 2013-2016 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 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
160 
161 	mpf->m_pkthdr.flowid = sgc->rss_hash;
162 	M_HASHTYPE_SET(mpf, M_HASHTYPE_OPAQUE_HASH);
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 
307 		M_HASHTYPE_SET(mpf, M_HASHTYPE_RSS_TCP_IPV4);
308 
309 	} else if (etype == ETHERTYPE_IPV6) {
310 		ip6 = (struct ip6_hdr *)(mpf->m_data + ETHER_HDR_LEN);
311 
312 		iplen = (th->th_off << 2) + sgc->payload_length;
313 
314 		ip6->ip6_plen = htons(iplen);
315 
316 		ha->ipv6_lro++;
317 
318 		M_HASHTYPE_SET(mpf, M_HASHTYPE_RSS_TCP_IPV6);
319 
320 	} else {
321 		m_freem(mpf);
322 
323 		if (sdsp->rx_free > ha->std_replenish)
324 			qla_replenish_normal_rx(ha, sdsp, r_idx);
325 		return 0;
326 	}
327 
328 	mpf->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID |
329 					CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
330 	mpf->m_pkthdr.csum_data = 0xFFFF;
331 
332 	mpf->m_pkthdr.flowid = sgc->rss_hash;
333 
334 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
335 
336 	(*ifp->if_input)(ifp, mpf);
337 
338 	if (sdsp->rx_free > ha->std_replenish)
339 		qla_replenish_normal_rx(ha, sdsp, r_idx);
340 
341 	return (0);
342 }
343 
344 static int
345 qla_rcv_cont_sds(qla_host_t *ha, uint32_t sds_idx, uint32_t comp_idx,
346 	uint32_t dcount, uint16_t *handle, uint16_t *nhandles)
347 {
348 	uint32_t i;
349 	uint16_t num_handles;
350 	q80_stat_desc_t *sdesc;
351 	uint32_t opcode;
352 
353 	*nhandles = 0;
354 	dcount--;
355 
356 	for (i = 0; i < dcount; i++) {
357 		comp_idx = (comp_idx + 1) & (NUM_STATUS_DESCRIPTORS-1);
358 		sdesc = (q80_stat_desc_t *)
359 				&ha->hw.sds[sds_idx].sds_ring_base[comp_idx];
360 
361 		opcode = Q8_STAT_DESC_OPCODE((sdesc->data[1]));
362 
363 		if (!opcode) {
364 			device_printf(ha->pci_dev, "%s: opcode=0 %p %p\n",
365 				__func__, (void *)sdesc->data[0],
366 				(void *)sdesc->data[1]);
367 			return -1;
368 		}
369 
370 		num_handles = Q8_SGL_STAT_DESC_NUM_HANDLES((sdesc->data[1]));
371 		if (!num_handles) {
372 			device_printf(ha->pci_dev, "%s: opcode=0 %p %p\n",
373 				__func__, (void *)sdesc->data[0],
374 				(void *)sdesc->data[1]);
375 			return -1;
376 		}
377 
378 		if (QL_ERR_INJECT(ha, INJCT_NUM_HNDLE_INVALID))
379 			num_handles = -1;
380 
381 		switch (num_handles) {
382 
383 		case 1:
384 			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
385 			break;
386 
387 		case 2:
388 			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
389 			*handle++ = Q8_SGL_STAT_DESC_HANDLE2((sdesc->data[0]));
390 			break;
391 
392 		case 3:
393 			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
394 			*handle++ = Q8_SGL_STAT_DESC_HANDLE2((sdesc->data[0]));
395 			*handle++ = Q8_SGL_STAT_DESC_HANDLE3((sdesc->data[0]));
396 			break;
397 
398 		case 4:
399 			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
400 			*handle++ = Q8_SGL_STAT_DESC_HANDLE2((sdesc->data[0]));
401 			*handle++ = Q8_SGL_STAT_DESC_HANDLE3((sdesc->data[0]));
402 			*handle++ = Q8_SGL_STAT_DESC_HANDLE4((sdesc->data[0]));
403 			break;
404 
405 		case 5:
406 			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
407 			*handle++ = Q8_SGL_STAT_DESC_HANDLE2((sdesc->data[0]));
408 			*handle++ = Q8_SGL_STAT_DESC_HANDLE3((sdesc->data[0]));
409 			*handle++ = Q8_SGL_STAT_DESC_HANDLE4((sdesc->data[0]));
410 			*handle++ = Q8_SGL_STAT_DESC_HANDLE5((sdesc->data[1]));
411 			break;
412 
413 		case 6:
414 			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
415 			*handle++ = Q8_SGL_STAT_DESC_HANDLE2((sdesc->data[0]));
416 			*handle++ = Q8_SGL_STAT_DESC_HANDLE3((sdesc->data[0]));
417 			*handle++ = Q8_SGL_STAT_DESC_HANDLE4((sdesc->data[0]));
418 			*handle++ = Q8_SGL_STAT_DESC_HANDLE5((sdesc->data[1]));
419 			*handle++ = Q8_SGL_STAT_DESC_HANDLE6((sdesc->data[1]));
420 			break;
421 
422 		case 7:
423 			*handle++ = Q8_SGL_STAT_DESC_HANDLE1((sdesc->data[0]));
424 			*handle++ = Q8_SGL_STAT_DESC_HANDLE2((sdesc->data[0]));
425 			*handle++ = Q8_SGL_STAT_DESC_HANDLE3((sdesc->data[0]));
426 			*handle++ = Q8_SGL_STAT_DESC_HANDLE4((sdesc->data[0]));
427 			*handle++ = Q8_SGL_STAT_DESC_HANDLE5((sdesc->data[1]));
428 			*handle++ = Q8_SGL_STAT_DESC_HANDLE6((sdesc->data[1]));
429 			*handle++ = Q8_SGL_STAT_DESC_HANDLE7((sdesc->data[1]));
430 			break;
431 
432 		default:
433 			device_printf(ha->pci_dev,
434 				"%s: invalid num handles %p %p\n",
435 				__func__, (void *)sdesc->data[0],
436 				(void *)sdesc->data[1]);
437 
438 			QL_ASSERT(ha, (0),\
439 			("%s: %s [nh, sds, d0, d1]=[%d, %d, %p, %p]\n",
440 			__func__, "invalid num handles", sds_idx, num_handles,
441 			(void *)sdesc->data[0],(void *)sdesc->data[1]));
442 
443 			qla_rcv_error(ha);
444 			return 0;
445 		}
446 		*nhandles = *nhandles + num_handles;
447 	}
448 	return 0;
449 }
450 
451 /*
452  * Name: qla_rcv_isr
453  * Function: Main Interrupt Service Routine
454  */
455 static uint32_t
456 qla_rcv_isr(qla_host_t *ha, uint32_t sds_idx, uint32_t count)
457 {
458 	device_t dev;
459 	qla_hw_t *hw;
460 	uint32_t comp_idx, c_idx = 0, desc_count = 0, opcode;
461 	volatile q80_stat_desc_t *sdesc, *sdesc0 = NULL;
462 	uint32_t ret = 0;
463 	qla_sgl_comp_t sgc;
464 	uint16_t nhandles;
465 	uint32_t sds_replenish_threshold = 0;
466 	uint32_t r_idx = 0;
467 	qla_sds_t *sdsp;
468 
469 	dev = ha->pci_dev;
470 	hw = &ha->hw;
471 
472 	hw->sds[sds_idx].rcv_active = 1;
473 	if (ha->flags.stop_rcv) {
474 		hw->sds[sds_idx].rcv_active = 0;
475 		return 0;
476 	}
477 
478 	QL_DPRINT2(ha, (dev, "%s: [%d]enter\n", __func__, sds_idx));
479 
480 	/*
481 	 * receive interrupts
482 	 */
483 	comp_idx = hw->sds[sds_idx].sdsr_next;
484 
485 	while (count-- && !ha->flags.stop_rcv) {
486 
487 		sdesc = (q80_stat_desc_t *)
488 				&hw->sds[sds_idx].sds_ring_base[comp_idx];
489 
490 		opcode = Q8_STAT_DESC_OPCODE((sdesc->data[1]));
491 
492 		if (!opcode)
493 			break;
494 
495 		hw->sds[sds_idx].intr_count++;
496 		switch (opcode) {
497 
498 		case Q8_STAT_DESC_OPCODE_RCV_PKT:
499 
500 			desc_count = 1;
501 
502 			bzero(&sgc, sizeof(qla_sgl_comp_t));
503 
504 			sgc.rcv.pkt_length =
505 				Q8_STAT_DESC_TOTAL_LENGTH((sdesc->data[0]));
506 			sgc.rcv.num_handles = 1;
507 			sgc.rcv.handle[0] =
508 				Q8_STAT_DESC_HANDLE((sdesc->data[0]));
509 			sgc.rcv.chksum_status =
510 				Q8_STAT_DESC_STATUS((sdesc->data[1]));
511 
512 			sgc.rcv.rss_hash =
513 				Q8_STAT_DESC_RSS_HASH((sdesc->data[0]));
514 
515 			if (Q8_STAT_DESC_VLAN((sdesc->data[1]))) {
516 				sgc.rcv.vlan_tag =
517 					Q8_STAT_DESC_VLAN_ID((sdesc->data[1]));
518 			}
519 			qla_rx_intr(ha, &sgc.rcv, sds_idx);
520 			break;
521 
522 		case Q8_STAT_DESC_OPCODE_SGL_RCV:
523 
524 			desc_count =
525 				Q8_STAT_DESC_COUNT_SGL_RCV((sdesc->data[1]));
526 
527 			if (desc_count > 1) {
528 				c_idx = (comp_idx + desc_count -1) &
529 						(NUM_STATUS_DESCRIPTORS-1);
530 				sdesc0 = (q80_stat_desc_t *)
531 					&hw->sds[sds_idx].sds_ring_base[c_idx];
532 
533 				if (Q8_STAT_DESC_OPCODE((sdesc0->data[1])) !=
534 						Q8_STAT_DESC_OPCODE_CONT) {
535 					desc_count = 0;
536 					break;
537 				}
538 			}
539 
540 			bzero(&sgc, sizeof(qla_sgl_comp_t));
541 
542 			sgc.rcv.pkt_length =
543 				Q8_STAT_DESC_TOTAL_LENGTH_SGL_RCV(\
544 					(sdesc->data[0]));
545 			sgc.rcv.chksum_status =
546 				Q8_STAT_DESC_STATUS((sdesc->data[1]));
547 
548 			sgc.rcv.rss_hash =
549 				Q8_STAT_DESC_RSS_HASH((sdesc->data[0]));
550 
551 			if (Q8_STAT_DESC_VLAN((sdesc->data[1]))) {
552 				sgc.rcv.vlan_tag =
553 					Q8_STAT_DESC_VLAN_ID((sdesc->data[1]));
554 			}
555 
556 			QL_ASSERT(ha, (desc_count <= 2) ,\
557 				("%s: [sds_idx, data0, data1]="\
558 				"%d, %p, %p]\n", __func__, sds_idx,\
559 				(void *)sdesc->data[0],\
560 				(void *)sdesc->data[1]));
561 
562 			sgc.rcv.num_handles = 1;
563 			sgc.rcv.handle[0] =
564 				Q8_STAT_DESC_HANDLE((sdesc->data[0]));
565 
566 			if (qla_rcv_cont_sds(ha, sds_idx, comp_idx, desc_count,
567 				&sgc.rcv.handle[1], &nhandles)) {
568 				device_printf(dev,
569 					"%s: [sds_idx, dcount, data0, data1]="
570 					 "[%d, %d, 0x%llx, 0x%llx]\n",
571 					__func__, sds_idx, desc_count,
572 					(long long unsigned int)sdesc->data[0],
573 					(long long unsigned int)sdesc->data[1]);
574 				desc_count = 0;
575 				break;
576 			}
577 
578 			sgc.rcv.num_handles += nhandles;
579 
580 			qla_rx_intr(ha, &sgc.rcv, sds_idx);
581 
582 			break;
583 
584 		case Q8_STAT_DESC_OPCODE_SGL_LRO:
585 
586 			desc_count =
587 				Q8_STAT_DESC_COUNT_SGL_LRO((sdesc->data[1]));
588 
589 			if (desc_count > 1) {
590 				c_idx = (comp_idx + desc_count -1) &
591 						(NUM_STATUS_DESCRIPTORS-1);
592 				sdesc0 = (q80_stat_desc_t *)
593 					&hw->sds[sds_idx].sds_ring_base[c_idx];
594 
595 				if (Q8_STAT_DESC_OPCODE((sdesc0->data[1])) !=
596 						Q8_STAT_DESC_OPCODE_CONT) {
597 					desc_count = 0;
598 					break;
599 				}
600 			}
601 			bzero(&sgc, sizeof(qla_sgl_comp_t));
602 
603 			sgc.lro.payload_length =
604 			Q8_STAT_DESC_TOTAL_LENGTH_SGL_RCV((sdesc->data[0]));
605 
606 			sgc.lro.rss_hash =
607 				Q8_STAT_DESC_RSS_HASH((sdesc->data[0]));
608 
609 			sgc.lro.num_handles = 1;
610 			sgc.lro.handle[0] =
611 				Q8_STAT_DESC_HANDLE((sdesc->data[0]));
612 
613 			if (Q8_SGL_LRO_STAT_TS((sdesc->data[1])))
614 				sgc.lro.flags |= Q8_LRO_COMP_TS;
615 
616 			if (Q8_SGL_LRO_STAT_PUSH_BIT((sdesc->data[1])))
617 				sgc.lro.flags |= Q8_LRO_COMP_PUSH_BIT;
618 
619 			sgc.lro.l2_offset =
620 				Q8_SGL_LRO_STAT_L2_OFFSET((sdesc->data[1]));
621 			sgc.lro.l4_offset =
622 				Q8_SGL_LRO_STAT_L4_OFFSET((sdesc->data[1]));
623 
624 			if (Q8_STAT_DESC_VLAN((sdesc->data[1]))) {
625 				sgc.lro.vlan_tag =
626 					Q8_STAT_DESC_VLAN_ID((sdesc->data[1]));
627 			}
628 
629 			QL_ASSERT(ha, (desc_count <= 7) ,\
630 				("%s: [sds_idx, data0, data1]="\
631 				 "[%d, 0x%llx, 0x%llx]\n",\
632 				__func__, sds_idx,\
633 				(long long unsigned int)sdesc->data[0],\
634 				(long long unsigned int)sdesc->data[1]));
635 
636 			if (qla_rcv_cont_sds(ha, sds_idx, comp_idx,
637 				desc_count, &sgc.lro.handle[1], &nhandles)) {
638 				device_printf(dev,
639 				"%s: [sds_idx, data0, data1]="\
640 				 "[%d, 0x%llx, 0x%llx]\n",\
641 				__func__, sds_idx,\
642 				(long long unsigned int)sdesc->data[0],\
643 				(long long unsigned int)sdesc->data[1]);
644 
645 				desc_count = 0;
646 				break;
647 			}
648 
649 			sgc.lro.num_handles += nhandles;
650 
651 			if (qla_lro_intr(ha, &sgc.lro, sds_idx)) {
652 				device_printf(dev,
653 				"%s: [sds_idx, data0, data1]="\
654 				 "[%d, 0x%llx, 0x%llx]\n",\
655 				__func__, sds_idx,\
656 				(long long unsigned int)sdesc->data[0],\
657 				(long long unsigned int)sdesc->data[1]);
658 				device_printf(dev,
659 				"%s: [comp_idx, c_idx, dcount, nhndls]="\
660 				 "[%d, %d, %d, %d]\n",\
661 				__func__, comp_idx, c_idx, desc_count,
662 				sgc.lro.num_handles);
663 				if (desc_count > 1) {
664 				device_printf(dev,
665 				"%s: [sds_idx, data0, data1]="\
666 				 "[%d, 0x%llx, 0x%llx]\n",\
667 				__func__, sds_idx,\
668 				(long long unsigned int)sdesc0->data[0],\
669 				(long long unsigned int)sdesc0->data[1]);
670 				}
671 			}
672 
673 			break;
674 
675 		default:
676 			device_printf(dev, "%s: default 0x%llx!\n", __func__,
677 					(long long unsigned int)sdesc->data[0]);
678 			break;
679 		}
680 
681 		if (desc_count == 0)
682 			break;
683 
684 		sds_replenish_threshold += desc_count;
685 
686 
687 		while (desc_count--) {
688 			sdesc->data[0] = 0ULL;
689 			sdesc->data[1] = 0ULL;
690 			comp_idx = (comp_idx + 1) & (NUM_STATUS_DESCRIPTORS-1);
691 			sdesc = (q80_stat_desc_t *)
692 				&hw->sds[sds_idx].sds_ring_base[comp_idx];
693 		}
694 
695 		if (sds_replenish_threshold > ha->hw.sds_cidx_thres) {
696 			sds_replenish_threshold = 0;
697 			if (hw->sds[sds_idx].sdsr_next != comp_idx) {
698 				QL_UPDATE_SDS_CONSUMER_INDEX(ha, sds_idx,\
699 					comp_idx);
700 			}
701 			hw->sds[sds_idx].sdsr_next = comp_idx;
702 		}
703 	}
704 
705 	if (ha->flags.stop_rcv)
706 		goto qla_rcv_isr_exit;
707 
708 	if (hw->sds[sds_idx].sdsr_next != comp_idx) {
709 		QL_UPDATE_SDS_CONSUMER_INDEX(ha, sds_idx, comp_idx);
710 		hw->sds[sds_idx].sdsr_next = comp_idx;
711 	} else {
712 		hw->sds[sds_idx].spurious_intr_count++;
713 
714 		if (ha->hw.num_rds_rings > 1)
715 			r_idx = sds_idx;
716 
717 		sdsp = &ha->hw.sds[sds_idx];
718 
719 		if (sdsp->rx_free > ha->std_replenish)
720 			qla_replenish_normal_rx(ha, sdsp, r_idx);
721 	}
722 
723 	sdesc = (q80_stat_desc_t *)&hw->sds[sds_idx].sds_ring_base[comp_idx];
724 	opcode = Q8_STAT_DESC_OPCODE((sdesc->data[1]));
725 
726 	if (opcode)
727 		ret = -1;
728 
729 qla_rcv_isr_exit:
730 	hw->sds[sds_idx].rcv_active = 0;
731 
732 	return (ret);
733 }
734 
735 void
736 ql_mbx_isr(void *arg)
737 {
738 	qla_host_t *ha;
739 	uint32_t data;
740 	uint32_t prev_link_state;
741 
742 	ha = arg;
743 
744 	if (ha == NULL) {
745 		device_printf(ha->pci_dev, "%s: arg == NULL\n", __func__);
746 		return;
747 	}
748 
749 	data = READ_REG32(ha, Q8_FW_MBOX_CNTRL);
750 	if ((data & 0x3) != 0x1) {
751 		WRITE_REG32(ha, ha->hw.mbx_intr_mask_offset, 0);
752 		return;
753 	}
754 
755 	data = READ_REG32(ha, Q8_FW_MBOX0);
756 
757 	if ((data & 0xF000) != 0x8000)
758 		return;
759 
760 	data = data & 0xFFFF;
761 
762 	switch (data) {
763 
764 	case 0x8001:  /* It's an AEN */
765 
766 		ha->hw.cable_oui = READ_REG32(ha, (Q8_FW_MBOX0 + 4));
767 
768 		data = READ_REG32(ha, (Q8_FW_MBOX0 + 8));
769 		ha->hw.cable_length = data & 0xFFFF;
770 
771 		data = data >> 16;
772 		ha->hw.link_speed = data & 0xFFF;
773 
774 		data = READ_REG32(ha, (Q8_FW_MBOX0 + 12));
775 
776 		prev_link_state =  ha->hw.link_up;
777 		ha->hw.link_up = (((data & 0xFF) == 0) ? 0 : 1);
778 
779 		if (prev_link_state !=  ha->hw.link_up) {
780 			if (ha->hw.link_up)
781 				if_link_state_change(ha->ifp, LINK_STATE_UP);
782 			else
783 				if_link_state_change(ha->ifp, LINK_STATE_DOWN);
784 		}
785 
786 
787 		ha->hw.module_type = ((data >> 8) & 0xFF);
788 		ha->hw.flags.fduplex = (((data & 0xFF0000) == 0) ? 0 : 1);
789 		ha->hw.flags.autoneg = (((data & 0xFF000000) == 0) ? 0 : 1);
790 
791 		data = READ_REG32(ha, (Q8_FW_MBOX0 + 16));
792 		ha->hw.flags.loopback_mode = data & 0x03;
793 
794 		ha->hw.link_faults = (data >> 3) & 0xFF;
795 
796 		break;
797 
798         case 0x8100:
799 		ha->hw.imd_compl=1;
800 		break;
801 
802         case 0x8101:
803                 ha->async_event = 1;
804                 ha->hw.aen_mb0 = 0x8101;
805                 ha->hw.aen_mb1 = READ_REG32(ha, (Q8_FW_MBOX0 + 4));
806                 ha->hw.aen_mb2 = READ_REG32(ha, (Q8_FW_MBOX0 + 8));
807                 ha->hw.aen_mb3 = READ_REG32(ha, (Q8_FW_MBOX0 + 12));
808                 ha->hw.aen_mb4 = READ_REG32(ha, (Q8_FW_MBOX0 + 16));
809                 break;
810 
811         case 0x8110:
812                 /* for now just dump the registers */
813                 {
814                         uint32_t ombx[5];
815 
816                         ombx[0] = READ_REG32(ha, (Q8_FW_MBOX0 + 4));
817                         ombx[1] = READ_REG32(ha, (Q8_FW_MBOX0 + 8));
818                         ombx[2] = READ_REG32(ha, (Q8_FW_MBOX0 + 12));
819                         ombx[3] = READ_REG32(ha, (Q8_FW_MBOX0 + 16));
820                         ombx[4] = READ_REG32(ha, (Q8_FW_MBOX0 + 20));
821 
822                         device_printf(ha->pci_dev, "%s: "
823                                 "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
824                                 __func__, data, ombx[0], ombx[1], ombx[2],
825                                 ombx[3], ombx[4]);
826                 }
827 
828                 break;
829 
830         case 0x8130:
831                 /* sfp insertion aen */
832                 device_printf(ha->pci_dev, "%s: sfp inserted [0x%08x]\n",
833                         __func__, READ_REG32(ha, (Q8_FW_MBOX0 + 4)));
834                 break;
835 
836         case 0x8131:
837                 /* sfp removal aen */
838                 device_printf(ha->pci_dev, "%s: sfp removed]\n", __func__);
839                 break;
840 
841 	case 0x8140:
842 		{
843 			uint32_t ombx[3];
844 
845 			ombx[0] = READ_REG32(ha, (Q8_FW_MBOX0 + 4));
846 			ombx[1] = READ_REG32(ha, (Q8_FW_MBOX0 + 8));
847 			ombx[2] = READ_REG32(ha, (Q8_FW_MBOX0 + 12));
848 
849 			device_printf(ha->pci_dev, "%s: "
850 				"0x%08x 0x%08x 0x%08x 0x%08x \n",
851 				__func__, data, ombx[0], ombx[1], ombx[2]);
852 		}
853 		break;
854 
855 	default:
856 		device_printf(ha->pci_dev, "%s: AEN[0x%08x]\n", __func__, data);
857 		break;
858 	}
859 	WRITE_REG32(ha, Q8_FW_MBOX_CNTRL, 0x0);
860 	WRITE_REG32(ha, ha->hw.mbx_intr_mask_offset, 0x0);
861 	return;
862 }
863 
864 
865 static void
866 qla_replenish_normal_rx(qla_host_t *ha, qla_sds_t *sdsp, uint32_t r_idx)
867 {
868 	qla_rx_buf_t *rxb;
869 	int count = sdsp->rx_free;
870 	uint32_t rx_next;
871 	qla_rdesc_t *rdesc;
872 
873 	/* we can play with this value via a sysctl */
874 	uint32_t replenish_thresh = ha->hw.rds_pidx_thres;
875 
876 	rdesc = &ha->hw.rds[r_idx];
877 
878 	rx_next = rdesc->rx_next;
879 
880 	while (count--) {
881 		rxb = sdsp->rxb_free;
882 
883 		if (rxb == NULL)
884 			break;
885 
886 		sdsp->rxb_free = rxb->next;
887 		sdsp->rx_free--;
888 
889 		if (ql_get_mbuf(ha, rxb, NULL) == 0) {
890 			qla_set_hw_rcv_desc(ha, r_idx, rdesc->rx_in,
891 				rxb->handle,
892 				rxb->paddr, (rxb->m_head)->m_pkthdr.len);
893 			rdesc->rx_in++;
894 			if (rdesc->rx_in == NUM_RX_DESCRIPTORS)
895 				rdesc->rx_in = 0;
896 			rdesc->rx_next++;
897 			if (rdesc->rx_next == NUM_RX_DESCRIPTORS)
898 				rdesc->rx_next = 0;
899 		} else {
900 			device_printf(ha->pci_dev,
901 				"%s: qla_get_mbuf [(%d),(%d),(%d)] failed\n",
902 				__func__, r_idx, rdesc->rx_in, rxb->handle);
903 
904 			rxb->m_head = NULL;
905 			rxb->next = sdsp->rxb_free;
906 			sdsp->rxb_free = rxb;
907 			sdsp->rx_free++;
908 
909 			break;
910 		}
911 		if (replenish_thresh-- == 0) {
912 			QL_UPDATE_RDS_PRODUCER_INDEX(ha, rdesc->prod_std,
913 				rdesc->rx_next);
914 			rx_next = rdesc->rx_next;
915 			replenish_thresh = ha->hw.rds_pidx_thres;
916 		}
917 	}
918 
919 	if (rx_next != rdesc->rx_next) {
920 		QL_UPDATE_RDS_PRODUCER_INDEX(ha, rdesc->prod_std,
921 			rdesc->rx_next);
922 	}
923 }
924 
925 void
926 ql_isr(void *arg)
927 {
928 	qla_ivec_t *ivec = arg;
929 	qla_host_t *ha ;
930 	int idx;
931 	qla_hw_t *hw;
932 	struct ifnet *ifp;
933 	uint32_t ret = 0;
934 
935 	ha = ivec->ha;
936 	hw = &ha->hw;
937 	ifp = ha->ifp;
938 
939 	if ((idx = ivec->sds_idx) >= ha->hw.num_sds_rings)
940 		return;
941 
942 	if (idx == 0)
943 		taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
944 
945 	ret = qla_rcv_isr(ha, idx, -1);
946 
947 	if (idx == 0)
948 		taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
949 
950 	if (!ha->flags.stop_rcv) {
951 		QL_ENABLE_INTERRUPTS(ha, idx);
952 	}
953 	return;
954 }
955 
956