📄 if_fza.c
字号:
tlen = len = sp->rmc & RMC_PBC_MASK; /* * check the last xmt descriptor */ last = sc->tindex + len/XMTSEGSIZE - (((len % XMTSEGSIZE) != 0) ? 0 : 1); /* * last descriptor not own by host */ if( sc->tring[last % sc->nsmtxmt].own & FZA_RMC_OWN ) { sc->tsmtindex = index ; return; } /* * copy the data from SMT XMT ring to RMC XMT ring */ nring = 0; smtbp = (caddr_t)(sp->buf_addr + sc->basereg); while(len > 0) { tp = &sc->tring[sc->tindex]; tbp = (caddr_t)FZAXMTADDR(tp,sc->basereg); fzacpy(smtbp,tbp,MIN(len,XMTSEGSIZE)); smtbp += MIN(len,XMTSEGSIZE); len -= MIN(len,XMTSEGSIZE); if(nring) { tp->own = FZA_RMC_OWN; tp->rmc = 0; } sc->tindex = ++sc->tindex % sc->nrmcxmt; nring++; } if(nring > 1 ) { tpstart->rmc = FZA_SOP | FZA_XMT_VBC | tlen; if(sc->tindex) sc->tring[sc->tindex-1].rmc = FZA_EOP ; else sc->tring[sc->nrmcxmt-1].rmc = FZA_EOP; } else tpstart->rmc = FZA_SOP | FZA_EOP | FZA_XMT_VBC | tlen; tpstart->own = FZA_RMC_OWN; tpstart->xmt_mbuf = (struct mbuf *)0; tmp = tpstart->own ; /* * give back the ownership to adapter */ sp->own &= ~FZA_HOST_OWN; sc->nxmit++; } /* * notice the port that one or more transmit packet is pending */ sc->reg_ctla |= XMT_POLL; wbflush(); sc->tsmtindex = index ;} /* * FZA command interrupt routine */fzacmdint(unit)int unit;{ register struct fza_softc *sc = &fza_softc[unit]; register FZACMDRING *cp; register FZACMD_BUF *xcmd; register int index; struct mbuf *m; for ( index = (sc->lcmdindex + 1) % NFZACMD, cp = &sc->cmdring[index]; (index != sc->cmdindex ) && (cp->own); index = ++index % NFZACMD ,cp = &sc->cmdring[index] ) { /* * process the cmd descriptor */ if(cp->status_id == 0 ) { /* command successed */ xcmd = (FZACMD_BUF *) (cp->buf_addr + sc->basereg) ; switch(cp->cmdid) { case CMD_RDCNTR: /* copy the counter*/ if(fzadebug) sc->fza_debug.cmdcnt.rdcntr++; bcopy(xcmd,sc->ctrblk,sizeof(struct _fzactrs)); break; case CMD_STATUS: if(fzadebug) sc->fza_debug.cmdcnt.status++; bcopy(xcmd,sc->statusblk,sizeof(structfzastatus)); break; case CMD_MODCAM: if(fzadebug) sc->fza_debug.cmdcnt.modcam++; break; case CMD_SETCHAR: if(fzadebug) sc->fza_debug.cmdcnt.setchar++; break; case CMD_RDCAM: if(fzadebug) sc->fza_debug.cmdcnt.rdcam++; bcopy(xcmd,&sc->is_multi[0][0],512); break; case CMD_MODPROM: if(fzadebug) sc->fza_debug.cmdcnt.modprom++; break; case CMD_PARAM: if(fzadebug) sc->fza_debug.cmdcnt.param++; break; case CMD_INIT: if(fzadebug) sc->fza_debug.cmdcnt.init++; break; case CMD_NOP: break; default: if(fzadebug) mprintf("fza%d: unknown command id %d\n",unit,cp->cmdid); break; } } else { /* error command */ printf("fza%d: command failed, ",unit); fzacmdstatus(sc,cp->status_id,unit,"fzacmdint"); } } if(index) sc->lcmdindex = index - 1; else sc->lcmdindex = NFZACMD - 1;}/* * FZA transmit interrupt routine */fzatint(unit)int unit;{ register struct fza_softc *sc = &fza_softc[unit]; register FZAXMTRING *tp; register struct mbuf *m0; register int index,len = 0; struct mbuf *mp; struct fddi_header *fh; /* * Process all outstanding transmits completed by * the port. */ for (index = (sc->ltindex + 1)%sc->nrmcxmt ,tp = &sc->tring[index]; (sc->nxmit > 0) && !(tp->own & FZA_RMC_OWN) ; index = ++index % sc->nrmcxmt, tp = &sc->tring[index]) { /* * if this is a start packet, process it. if not, do nothing */ if(tp->rmc & FZA_SOP ) { /* * Process xmit descriptor, we have no way to know the * packet trasnmit status */ sc->is_if.if_opackets++; mp = (struct mbuf *)tp->xmt_mbuf; tp->xmt_mbuf = (struct mbuf *)0; if( tp->rmc & FZA_XMT_SUCCESS ) { fstc_bytesent += tp->rmc & RMC_PBC_MASK; if( fstc_pdusent != 0xffffffff) fstc_pdusent++; /* * Loop back any LLC broadcasts we send * * mp == 0 that means this is a SMT packet * this packet was copy from SMT XMT ring */ if(mp) { /* LLC packet */ fh = mtod(mp, struct fddi_header *); if ( (!bcmp(&fh->fddi_dhost[0], etherbroadcastaddr, 6)) || (sc->is_if.if_flags & IFF_PFCOPYALL) ) { m0 = mp; while (m0) { len += m0->m_len; m0 = m0->m_next; } fzaread(sc, 0, len, mp); } else { if( fh->fddi_dhost[0] & 1 ) { fstc_mbytesent += tp->rmc & RMC_PBC_MASK; if(fstc_mpdusent != 0xffffffff) fstc_mpdusent++; } m_freem(mp); } } } else { if(mp) m_freem(mp); sc->is_if.if_oerrors++; } sc->nxmit--; } } if(index) sc->ltindex = index - 1; /* Last xmit processed */ else sc->ltindex = sc->nrmcxmt - 1;} /* * FZA receive interrupt routine */fzarint(unit)int unit;{ register struct fza_softc *sc = &fza_softc[unit]; register int index,len; register FZARCVRING *rp; struct mbuf *m,*m1,*mp; struct fddi_header *fptr; struct rmbuf *bp; int nrcv = 0; int fddi_type; /* * Process all incoming packets on the receive ring. Stop if * we get to the current receive index to avoid locking out * the system, but give back one descriptor for each one we * process to keep the device busy. * * */ for (index = sc->rindex, rp = &sc->rring[index], bp = &sc->rmbuf[index]; (rp->rcv_own & FZA_RCV_OWN) && nrcv < NFZARCV - 1; index = sc->rindex = ++index % NFZARCV, rp = &sc->rring[index], bp = &sc->rmbuf[index], nrcv++) { /* * check the DMA RCV status. If no error, process it * we only process the LLC and SMT frame for decword */ if(!(rp->rmc & FZA_RCV_ERROR)) { len = rp->rmc & RMC_PBC_MASK ; if ( len > FDDIMAX ) { /* Frame too long */ if(fstc_pdulen != 0xffffffff) fstc_pdulen++; goto error; } else { fptr = (struct fddi_header *)PHYS_TO_K1(bp->phymbufa); switch (fptr->fddi_fc & ~FDDIFC_Z ) { /* take out the priority */ case FDDIFC_LLC_ASYNC: /* for LLC frame */ case FDDIFC_LLC_SYNC: if( len < FDDILLCMIM ) { if(fzadebug) printf("fza%d: LLC frame too short - frame len %d",unit,len); if(fstc_pdulen != 0xffffffff) fstc_pdulen++; goto error; } fddi_type = FZA_LLC; /* * The length reported by RMC is including one * byte Frame Control, real data and 4 bytes CRC. * The driver interprets the frame as 4 bytes * FDDI header ( including one byte Frame Control) * and real data. So, we need to decrement one * for the length. */ len--; break; case FDDIFC_SMT: /* for SMT frame */ if( len < FDDISMTMIM) { if(fzadebug) printf("fza%d: LLC frame too short - frame len %d",unit,len); if(fstc_pdulen != 0xffffffff) fstc_pdulen++; goto error; } fddi_type = FZA_SMT; /* * mismatch with the firmware * RMC told us the wrong length */ len = len + 3 ; break; case FDDIFC_MAC: default: if(fzadebug) mprintf("fza%d: unrecognize frame FC 0x%2x\n",unit,fptr->fddi_fc); fzanundrop++; goto error; break; } } /* * Allocate a pair of new mbufs for the current * receive descriptor. * * Each receive buffer will use two cluster mbufs. * * The first cut will be : * * If the size of packet less than 4K, then the second * mbuf will be reused. * * The second cut will be: * * If the size of FDDI frame less than the small * mbuf length (which is MLEN = 108), driver will * allocate a small mbuf then data copy the * packet to it. This will save a large cluster mbuf. * * In addition, if the second mbuf only is used for * less than MLEN size, a small mbuf will be allocated * and data copy the rest of packet from the second * cluster mbuf to this small mbuf. * */ if(fzadebug > 1 ) { printf("fzarint: got packet size %d type",len); if(fddi_type == FZA_LLC ) printf(" LLC frame \n"); else printf(" SMT frame \n"); } if(len > MLEN ) { FZAMCLGET(mp) } else { MGET(mp, M_DONTWAIT, MT_DATA) } m = bp->mbufa ; if ( mp ) { if ( len > M_CLUSTERSZ ) { FZAMCLGET(m1) if(m1) { clean_dcache(PHYS_TO_K0(bp->phymbufa),M_CLUSTERSZ); clean_dcache(PHYS_TO_K0(bp->phymbufb),len - M_CLUSTERSZ); m->m_next = bp->mbufb; m->m_next->m_len = len - M_CLUSTERSZ; fzanlarge++; } else { m_freem(mp); fzannombuf++; goto doinit; } } else if ( len > MLEN ) { m1 = bp->mbufb; clean_dcache(PHYS_TO_K0(bp->phymbufa),len); m->m_len = len; fzanmiddle++; } else { /* * if size < = MLEN */ bcopy((PHYS_TO_K1(bp->phymbufa)),mtod(mp,caddr_t),len); m = mp; m->m_len = len; mp = bp->mbufa; m1 = bp->mbufb; fzansmall++; } if(fddi_type == FZA_LLC ) fzaread (sc, m, len, (struct mbuf *)0); else { /* for SMT frame, just queue it */ if(IF_QFULL(&sc->is_smt)){ IF_DROP(&sc->is_smt); /* * increase the system buffer * unavailable */ sc->reg_ctla = SMT_RCV_OVERFLOW; fzansmtdrop++; m_freem(m); } else { fzansmtrcvd++; IF_ENQUEUE(&sc->is_smt,m); /* Save the RMC descriptor */ sc->smt_rmc[sc->smtrmcindex]= rp->rmc; sc->smtrmcindex = ++sc->smtrmcindex % IFQ_MAXLEN; } } fzainitdesc(rp,bp,mp,m1); } else { fzannombuf++; goto doinit; } } else { /* if error happened, paser the RMC descriptor */ if(fzadebug) mprintf("fza%d: recv err x%x\n",unit,rp->rmc); switch(rp->rmc & FZA_RCV_RCC ) { case FZA_RCV_OVERRUN: /* frame too long */ if(len == 8192 || len == 8191) fstc_pdulen++; else { if (fzadebug) printf("xfa%d: RMC FIFO Overflow",unit); } break; case FZA_RCV_INTERFACE_ERR:/* RMC/MAC interface error*/ /* * adapter should take care this * driver will never see this */ printf("fza%d: RMC/MAC interface error",unit); break; default: switch(rp->rmc & FZA_RCV_RCC_rrr) { case FZA_RCV_RCC_NORMAL: if(rp->rmc & FZA_RCV_RCC_C) { fstc_fcserror++; if(fzadebug) printf("fza%d: Block Check Error\n",unit); } else if ( !(rp->rmc & FZA_RCV_FSC) || (rp->rmc & FZA_RCV_FSB_E)){ fstc_fseerror++; if(fzadebug) printf("fza%d: Frame status error\n",unit); } break; case FZA_RCV_RCC_INVALID_LEN: fstc_pdualig++; if(fzadebug) printf("fza%d: Frame Alignment Error\n",unit); break; case FZA_RCV_RCC_SA_MATCHED: case FZA_RCV_RCC_DA_NOMATCHED: case FZA_RCV_RCC_RMC_ABORT: if(fzadebug) printf("fza%d: Hardware problem \n",unit); /* * go to halt state, log * the errors */ sc->reg_ctla = HALT; return; break; case FZA_RCV_RCC_FRAGMENT: case FZA_RCV_RCC_FORMAT_ERR: case FZA_RCV_MAC_RESET: if(fzadebug) printf("fza%d: Fragment or format error or MAC reset\n",unit); break; defualt: if(fzadebug) printf("fza%d: Wrong RMC descriptor report 0x%x \n",unit,rp->rmc); break; } break; } error: sc->is_if.if_ierrors++;doinit: fzainitdesc(rp,bp,bp->mbufa,bp->mbufb); } }}/* * FZA read routine. Pass input packets up to higher levels. */fzaread (sc, m, len, swloop) register struct fza_softc *sc; register int len; struct mbuf *m; struct mbuf *swloop;{ register struct fddi_header *eptr; register int off, resid; struct mbuf *swloop_tmp1; struct ether_header eh; struct protosw *pr; struct ifqueue *inq; /* * Not supporting the trailer protocol */ if (swloop) { eptr = mtod(swloop, struct fddi_header *); if ( swloop->m_len > sizeof(struct fddi_header)) m_adj(swloop, sizeof(struct fddi_header)); else { MFREE(swloop, swloop_tmp1); if ( ! swloop_tmp1 ) return; else swloop = swloop_tmp1; } } else eptr = mtod(m, struct fddi_header *); /* * Pull packet off interface. */ if (swloop) { m = m_copy(swloop, 0, M_COPYALL); m_freem(swloop); if (m == 0) return; } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -