]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/dev/qlxgbe/ql_isr.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / dev / qlxgbe / ql_isr.c
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         ifp->if_ipackets++;
160
161         mpf->m_pkthdr.flowid = sgc->rss_hash;
162         M_HASHTYPE_SET(mpf, M_HASHTYPE_OPAQUE);
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         M_HASHTYPE_SET(mpf, M_HASHTYPE_OPAQUE);
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                 break;
780
781         case 0x8100:
782                 ha->hw.imd_compl=1;
783                 break;
784
785         case 0x8101:
786                 ha->async_event = 1;
787                 ha->hw.aen_mb0 = 0x8101;
788                 ha->hw.aen_mb1 = READ_REG32(ha, (Q8_FW_MBOX0 + 4));
789                 ha->hw.aen_mb2 = READ_REG32(ha, (Q8_FW_MBOX0 + 8));
790                 ha->hw.aen_mb3 = READ_REG32(ha, (Q8_FW_MBOX0 + 12));
791                 ha->hw.aen_mb4 = READ_REG32(ha, (Q8_FW_MBOX0 + 16));
792                 break;
793
794         case 0x8110:
795                 /* for now just dump the registers */
796                 {
797                         uint32_t ombx[5];
798
799                         ombx[0] = READ_REG32(ha, (Q8_FW_MBOX0 + 4));
800                         ombx[1] = READ_REG32(ha, (Q8_FW_MBOX0 + 8));
801                         ombx[2] = READ_REG32(ha, (Q8_FW_MBOX0 + 12));
802                         ombx[3] = READ_REG32(ha, (Q8_FW_MBOX0 + 16));
803                         ombx[4] = READ_REG32(ha, (Q8_FW_MBOX0 + 20));
804
805                         device_printf(ha->pci_dev, "%s: "
806                                 "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
807                                 __func__, data, ombx[0], ombx[1], ombx[2],
808                                 ombx[3], ombx[4]);
809                 }
810
811                 break;
812
813         case 0x8130:
814                 /* sfp insertion aen */
815                 device_printf(ha->pci_dev, "%s: sfp inserted [0x%08x]\n",
816                         __func__, READ_REG32(ha, (Q8_FW_MBOX0 + 4)));
817                 break;
818
819         case 0x8131:
820                 /* sfp removal aen */
821                 device_printf(ha->pci_dev, "%s: sfp removed]\n", __func__);
822                 break;
823
824         default:
825                 device_printf(ha->pci_dev, "%s: AEN[0x%08x]\n", __func__, data);
826                 break;
827         }
828         WRITE_REG32(ha, Q8_FW_MBOX_CNTRL, 0x0);
829         WRITE_REG32(ha, ha->hw.mbx_intr_mask_offset, 0x0);
830         return;
831 }
832
833
834 static void
835 qla_replenish_normal_rx(qla_host_t *ha, qla_sds_t *sdsp, uint32_t r_idx)
836 {
837         qla_rx_buf_t *rxb;
838         int count = sdsp->rx_free;
839         uint32_t rx_next;
840         qla_rdesc_t *rdesc;
841
842         /* we can play with this value via a sysctl */
843         uint32_t replenish_thresh = ha->hw.rds_pidx_thres;
844
845         rdesc = &ha->hw.rds[r_idx];
846
847         rx_next = rdesc->rx_next;
848
849         while (count--) {
850                 rxb = sdsp->rxb_free;
851
852                 if (rxb == NULL)
853                         break;
854
855                 sdsp->rxb_free = rxb->next;
856                 sdsp->rx_free--;
857
858                 if (ql_get_mbuf(ha, rxb, NULL) == 0) {
859                         qla_set_hw_rcv_desc(ha, r_idx, rdesc->rx_in,
860                                 rxb->handle,
861                                 rxb->paddr, (rxb->m_head)->m_pkthdr.len);
862                         rdesc->rx_in++;
863                         if (rdesc->rx_in == NUM_RX_DESCRIPTORS)
864                                 rdesc->rx_in = 0;
865                         rdesc->rx_next++;
866                         if (rdesc->rx_next == NUM_RX_DESCRIPTORS)
867                                 rdesc->rx_next = 0;
868                 } else {
869                         device_printf(ha->pci_dev,
870                                 "%s: ql_get_mbuf [0,(%d),(%d)] failed\n",
871                                 __func__, rdesc->rx_in, rxb->handle);
872
873                         rxb->m_head = NULL;
874                         rxb->next = sdsp->rxb_free;
875                         sdsp->rxb_free = rxb;
876                         sdsp->rx_free++;
877
878                         break;
879                 }
880                 if (replenish_thresh-- == 0) {
881                         QL_UPDATE_RDS_PRODUCER_INDEX(ha, rdesc->prod_std,
882                                 rdesc->rx_next);
883                         rx_next = rdesc->rx_next;
884                         replenish_thresh = ha->hw.rds_pidx_thres;
885                 }
886         }
887
888         if (rx_next != rdesc->rx_next) {
889                 QL_UPDATE_RDS_PRODUCER_INDEX(ha, rdesc->prod_std,
890                         rdesc->rx_next);
891         }
892 }
893
894 void
895 ql_isr(void *arg)
896 {
897         qla_ivec_t *ivec = arg;
898         qla_host_t *ha ;
899         int idx;
900         qla_hw_t *hw;
901         struct ifnet *ifp;
902         uint32_t ret = 0;
903
904         ha = ivec->ha;
905         hw = &ha->hw;
906         ifp = ha->ifp;
907
908         if ((idx = ivec->sds_idx) >= ha->hw.num_sds_rings)
909                 return;
910
911         if (idx == 0)
912                 taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
913         
914         ret = qla_rcv_isr(ha, idx, -1);
915
916         if (idx == 0)
917                 taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
918
919         if (!ha->flags.stop_rcv) {
920                 QL_ENABLE_INTERRUPTS(ha, idx);
921         }
922         return;
923 }
924