📄 if_scs.c
字号:
/* * if the offset is nonzero then this is a * leading cut mbuf. We can only offset from the * beginning of a chain. If we encounter a * second offset mbuf we have to copy the data * to a page aligned buffer and map the new buffer. */ if (pgoff) { if (msg->off) break; msg->off = pgoff; } /* Turn virtual address into a kernel map index */#define mxtob(x) (((int)x - (int)Sysbase) >> PGSHIFT) frompte = &Sysmap[mxtob(dp)]; for (rem = pgoff + m->m_len; rem >= NBPG; rem -= NBPG) { *topte++ = *frompte++; len -= NBPG; Tbis(tova); tova += NBPG; } len += pgoff; /* the above loop has to be adjusted * for a mbuf that is offset */ /* * if there is still something left in this mbuf * we can still map it if there is no other data. * Otherwise we have to copy the * remainder to a buffer. */ if (rem) if (m->m_next) { break; } else { *topte++ = *frompte++; Tbis(tova); len -= rem; tova += rem; rem = 0; /* dont need to do this I think */ } m = m->m_next; } else break; } /* * the rest of the data is in small mbufs or is * not page aligned. * We grab as much space as needed and copy the * rest of the mbuf chain to it. */ if (m) { register int slen = 0; caddr_t clbuf_t; int alloc_len; caddr_t va = tova; /* * need things page aligned so grag at least a page */ if (len < NBPG) alloc_len = NBPG; else alloc_len = len; KM_ALLOC(clbuf_t, caddr_t, alloc_len, KM_DEVBUF, KM_NOWAIT); if (clbuf_t == 0) { if (scsnetdebug) printf("scsnet out: KM_ALLOC failed\n"); if (broadcast) m_freem(mchain); scscp->mchain = 0; smp_unlock(&scs_dst->lk_netsys); Scsnet_Return_ENOBUFS } scscp->clbuf_t = clbuf_t; /* save to free up later */ scscp->clbuf_len = alloc_len; /* save to free up later */ /* * map out the kmalloc'ed space and copy the remaining * data */ frompte = &kmempt[btokmemx((struct pte *) clbuf_t)]; for (i = rbtop(len) ; i > 0; i--) { *topte++ = *frompte++; Tbis(va); va += NBPG; } if (rem) { /* * take care of remainder from last big mbuf */#define remoff (m->m_len - rem) bcopy(mtod(m, caddr_t) + remoff, tova, rem);#undef remoff tova += rem; slen += rem; m = m->m_next; } while (m) { if ((slen += m->m_len) > len) { panic("scsnet: NO ROOM for tail mbuf"); } bcopy(mtod(m, caddr_t), tova, m->m_len); tova += m->m_len; m = m->m_next; } } msg->totlen = tova - (caddr_t)scsxtob(scscp->xpte) - msg->off; }#ifdef notdef tbsync(); /* for multi-processor translation buffer */#endif#ifdef mips /* * map buffer before we send it. Can not pre-map for mips box * because of the pte translation that occurs for the CI */ scscp->bufhdr.b_un.b_addr = (char *)scsxtob(scscp->xpte); scscp->bufhdr.b_bcount = msg->totlen + msg->off; scscp->bufhdr.b_flags = 0; scscp->csb.Sbh = &scscp->bufhdr; if ((status = scs_map_buf(&scscp->csb)) != RET_SUCCESS) { printf("scsnet: could not map transmit buffer, status=%x\n", status); if (broadcast) m_freem(mchain); scscp->mchain = 0; if (scscp->clbuf_t) KM_FREE(scscp->clbuf_t, KM_DEVBUF); smp_unlock(&scs_dst->lk_netsys); Scsnet_Return_ENOBUFS }#endif Move_bhandle(scscp->csb.lbhandle, msg->bhandle); /* send message to remote - do not free mbufs till response */ /* We will need a background timer to check up on things */ scscp->csb.Disposal = RECEIVE_BUF; /* for receive ack */ if ((status=scs_send_msg(&scscp->csb)) != RET_SUCCESS) { if (scsnetdebug) printf("scs_net: send failed, %x\n", status); if (broadcast) m_freem(mchain); scscp->mchain = 0; if (scscp->clbuf_t) KM_FREE(scscp->clbuf_t, KM_DEVBUF); smp_unlock(&scs_dst->lk_netsys); Scsnet_Return_ENOBUFS } scscp->state = SCSNET_BSTARTED; } else /* not a block transfer */ { notblock = 1; csb.connid = scs_dst->connid; if ((status=scs_alloc_dg(&csb))!=RET_SUCCESS) { if (scsnetdebug) printf("scsnet: scs_alloc_dg failed, status= %x\n", status); smp_unlock(&scs_dst->lk_netsys); Scsnet_Return_ENOBUFS } /* copy protocol type and data to scs buffer */ bcopy(&type, csb.buf, SCSNET_HDR_SIZ); off = csb.buf + SCSNET_HDR_SIZ; while (m) { bcopy(mtod(m, caddr_t), off, m->m_len); off += m->m_len; m = m->m_next; } if ((csb.size = off - csb.buf) > scs_dg_size) printf("scsnet data gram too large: %d\n", csb.size); csb.Disposal = DEALLOC_BUF; /* send data to remote host */ if ((status = scs_send_dg(&csb)) != RET_SUCCESS) printf("scsnet: send_dg failed, status= %d\n",status); } ifp->if_opackets++; smp_unlock(&scs_dst->lk_netsys); (void)splx( ipl ); /* start timer to ensure that we eventually free mbuf chain */ /* moved here to improve smp performance */ if (notblock == 0 && !scsnet_timer++) timeout(scsnet_watch, 0, scsnet_timeo); if (broadcast) { goto broadcastloop; } /* * do not free up mbuf chain if block transfer. We will free * the mbuf chain when we receive an acknowledgment */ if (notblock) m_freem(m0);#ifdef notdef /* * Check for more to send */ IF_DEQUEUE(&scsnetif.if_snd, m) if (m == 0) return(0); /* m contains temp info - the rest of the chain will * free up later. */ m0 = m->m_next; /* initialize variables and try to send */ notblock = broadcast = 0; dst = mtod(m, stuct sockaddr *); m = m0; m_free(m); goto start;#endif return(0);}/* * Process an ioctl request. */scsnet_ioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ int error = 0; switch (cmd) { case SIOCSIFADDR: /* * Everything else is done at a higher level. */ if (! (ifp->if_flags & IFF_UP) ) /* should use diff flag? */ if (scsnet_init()) return (EIO); ifp->if_flags |= IFF_UP; break; default: error = EINVAL; } return (error);}/* * scsnet_dgevent() - datagrams received here. copy data into mbufs * and insert them into appropriate queue (INET only for now) */voidscsnet_dgevent(csb)register CSB *csb;{ register struct ifnet *ifp = &scsnetif; register u_long totlen = csb->size; /* length of packet */ register u_char *cp = csb->buf; /* pointer to packet data */ register struct mbuf **mp; /* mp is the next spot in the * chain to assign mbuf */ struct mbuf *top = 0; /* beginning of new mbuf chain */ int ret; if (!(ifp->if_flags & IFF_UP)) goto requeue; /* copy data from scs buffer to mbuf chain */ mp = ⊤ while (totlen) { register struct mbuf *m; MGET(m, M_DONTWAIT, MT_DATA); if (m==0) { if (scsnetdebug) printf("scsnet_dgevent: could not copy csb to mbuf \n"); if (top) m_freem(top); goto requeue; } if (totlen >= CLBYTES) { struct mbuf *p; MCLGET(m, p); if (p==0) m->m_len = MIN(MLEN, totlen); else m->m_len = CLBYTES; } else m->m_len = MIN(MLEN, totlen); bcopy(cp, mtod(m, caddr_t), (unsigned)m->m_len); cp += m->m_len; *mp = m; mp = &m->m_next; totlen -= m->m_len; } /* enqueue packet on protocol queue */ ifp->if_ipackets++; Scsnet_enqueue(top) /* requeue buffer for reception */requeue: csb->Nbufs =0; if ((ret = scs_queue_dgs (csb)) != RET_SUCCESS) printf("scsnet_dgevent requeue failed 2, ret = %d\n", ret);}/* * scsnet_msgevent * Receive a message. The message is either a request for starting a * block transfer or an acknowledgment to the request. * If we are receiving an ack then we want to deallocate our message buffer. * If we are sending an ack we want to return the buffer to the receive * pool to prepare for new requests. */struct pte zeropte = {0,0,0,0,0,0,0,0};voidscsnet_msgevent(csb) register CSB *csb;{ register struct scsnet_msg *msg = (struct scsnet_msg *)csb->buf; register int totlen = msg->totlen; register struct scsnet_cntl *bp = 0; register struct mbuf *m = 0; register int recvx; caddr_t recvbuf; int status; if (msg->cmd == SCSNET_BCMD_REQUEST) { /* start block transfer from the remote host * First gather up required resources. * If can not get resources send back a negative ack. */ register int clen = csb->size - Scsnet_msg_hdr_siz; register struct mbuf *p; register struct ifnet *ifp = &scsnetif; void scsnet_freem(); struct mbuf *mclgetx(); if (!(ifp->if_flags & IFF_UP)) goto bad; MGET(m, M_DONTWAIT, MT_DATA) if (m==0) goto bad; if (clen > MLEN) { MCLGET(m,p) if (p==0) goto bad; } m->m_len = clen; /* * copy protocol header into mbuf */ bcopy(msg->proto_hdr, mtod(m, caddr_t), m->m_len); /* * get a free transfer control block */ smp_lock(&lk_scsnetrecvs, LK_RETRY); for (recvx=0, bp=scsnet_recvs; bp < &scsnet_recvs[SCSNET_RECVS]; bp++,recvx++) if (bp->state & SCSNET_BDONE) break; if (recvx >= SCSNET_RECVS) { if (scsnetdebug) printf("scsnet: could not allocate recvbuf\n"); smp_unlock(&lk_scsnetrecvs); goto bad; } bp->state = SCSNET_BSTARTED; smp_unlock(&lk_scsnetrecvs); KM_ALLOC(recvbuf, caddr_t, totlen, KM_DEVBUF, KM_NOWAIT); if (recvbuf == 0) { if (scsnetdebug) printf("scsnet: could not kmalloc recvbuf\n"); bp->state = SCSNET_BDONE; goto bad; } m->m_next = mclgetx(scsnet_freem, (int)recvbuf, recvbuf, totlen, M_DONTWAIT); if (m->m_next == 0) { KM_FREE(recvbuf, KM_DEVBUF); if (scsnetdebug) printf("scsnet: could not allocate recv cluster\n"); bp->state = SCSNET_BDONE; goto bad; } /* * set up buffer and map it */ bp->bufhdr.b_un.b_addr = recvbuf; bp->bufhdr.b_flags = 0; csb->Sbh = &bp->bufhdr; bp->bufhdr.b_bcount = msg->totlen; csb->Blockid = recvx; /* will identify us during BLOCK_DONE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -