c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * CDDL HEADER START
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * The contents of this file are subject to the terms of the
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * Common Development and Distribution License (the "License").
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * You may not use this file except in compliance with the License.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * See the License for the specific language governing permissions
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * and limitations under the License.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * When distributing Covered Code, include this CDDL HEADER in each
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
ead9bb4b1be81d7bbf8ed86ee41d6c1e58b069a3Yuri Pankov * If applicable, add the following below this CDDL HEADER, with the
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * fields enclosed by brackets "[]" replaced with your own identifying
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * information: Portions Copyright [yyyy] [name of copyright owner]
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * CDDL HEADER END
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * Copyright 2014 QLogic Corporation
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * The contents of this file are subject to the terms of the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * QLogic End User License (the "License").
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * You may not use this file except in compliance with the License.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * You can obtain a copy of the License at
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * http://www.qlogic.com/Resources/Documents/DriverDownloadHelp/
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * See the License for the specific language governing permissions
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * and limitations under the License.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 0, /* dma_attr_addr_lo */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 0, /* dma_attr_flags */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 0, /* dma_attr_addr_lo */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 0, /* dma_attr_flags */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic um_txpacket_t * BnxeTxPktAlloc(um_device_t * pUM, size_t size);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic inline void BnxeTxPktUnmap(um_txpacket_t * pTxPkt)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic void BnxeTxPktsFree(um_txpacket_t * pTxPkt)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov for (i = 0; i < BNXE_MAX_DMA_HANDLES_PER_PKT; i++)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic void BnxeTxPktsFreeList(s_list_t * pPktList)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt = (um_txpacket_t *)s_list_pop_head(pPktList);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * Free the mblk and all frag mappings used by each packet in the list
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * and then put the entire list on the free queue for immediate use.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov for (pTxPkt = (um_txpacket_t *)s_list_peek_head(pPktList);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt = (um_txpacket_t *)s_list_next_entry(&pTxPkt->lm_pkt.link))
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov s_list_add_tail(&pUM->txq[idx].freeTxDescQ, pPktList);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov/* Must be called with TX lock held!!! */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic int BnxeTxSendWaitingPkt(um_device_t * pUM,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt = (um_txpacket_t *)s_list_peek_head(&pTxQ->waitTxDescQ);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pTxPkt->frag_list.cnt + 2 > pLmTxChain->bd_chain.bd_left)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt = (um_txpacket_t *)s_list_pop_head(&pTxQ->waitTxDescQ);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov rc = lm_send_packet(pLM, idx, &pTxPkt->lm_pkt, &pTxPkt->frag_list);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeCheckAccHandle(pLM->vars.reg_handle[BAR_0]) != DDI_FM_OK)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_DEGRADED);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * Send failed (probably not enough BDs available)...
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * Put the packet back at the head of the wait queue.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov s_list_push_head(&pTxQ->waitTxDescQ, &pTxPkt->lm_pkt.link);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pktsTxed = lm_get_packets_sent(&pUM->lm_dev, idx, &tmpList);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeCheckAccHandle(pUM->lm_dev.vars.reg_handle[BAR_0]) != DDI_FM_OK)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_DEGRADED);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if ((pktsTxed + s_list_entry_cnt(&pTxQ->sentTxQ)) >=
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* no need to notify the stack */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pTxQ->noTxCredits & BNXE_TX_RESOURCES_NO_CREDIT)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov (pLmTxChain->bd_chain.bd_left >= BNXE_MAX_DMA_FRAGS_PER_PKT))
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov atomic_and_32(&pTxQ->noTxCredits, ~BNXE_TX_RESOURCES_NO_CREDIT);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if ((pTxQ->noTxCredits & BNXE_TX_RESOURCES_NO_DESC) &&
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov (s_list_entry_cnt(&pTxQ->freeTxDescQ) > pTxQ->thresh_pdwm))
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov atomic_and_32(&pTxQ->noTxCredits, ~BNXE_TX_RESOURCES_NO_DESC);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeLogInfo(pUM, "FCoE tx credit ok, no upcall!");
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* notify the stack that tx resources are now available */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov#if defined(BNXE_RINGS) && (defined(__S11) || defined(__S12))
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov mac_tx_ring_update(pUM->pMac, pTxQ->ringHandle);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic inline int BnxeTxPktMapFrag(um_device_t * pUM,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pTxPkt->num_handles == BNXE_MAX_DMA_HANDLES_PER_PKT)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pTxPkt->frag_list.cnt >= BNXE_MAX_DMA_FRAGS_PER_PKT)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov dmaHandle = pTxPkt->dmaHandles[pTxPkt->num_handles];
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeLogWarn(pUM, "Failed to bind DMA address for tx packet (%d)", rc);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * ddi_dma_addr_bind_handle() correctly returns an error if the physical
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * fragment count exceeds the maximum fragment count specified in the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * ddi_dma_attrib structure for the current pMblk. However, a packet can
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * span multiple mblk's. The purpose of the check below is to make sure we
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * do not overflow our fragment count limit based on what has already been
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * mapped from this packet.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * Going to try a partial dma so (re)set count to the remaining number
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * of dma fragments that are available leaving one fragment at the end.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov count = (BNXE_MAX_DMA_FRAGS_PER_PKT - 1 - pTxPkt->frag_list.cnt);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * No more dma fragments are available. This fragment was not
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * mapped and will be copied into the copy buffer along with the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * rest of the packet data.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pFrag = &pTxPkt->frag_list.frag_arr[pTxPkt->frag_list.cnt];
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* map "count" dma fragments */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * Move the mblk's read pointer past the data that was bound to a DMA
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * fragment. Any remaining data will get copied into the copy buffer.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* Walk the chain to get the total pkt length... */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov for (pMblk = pTxPkt->pMblk; pMblk; pMblk = pMblk->b_cont)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * If the packet length is under the tx copy threshold then copy
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * the all data into the copy buffer.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov for (pMblk = pTxPkt->pMblk; pMblk; pMblk = pMblk->b_cont)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pCopyFrag->addr.as_u64 = pTxPkt->cbPhysAddr.as_u64;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* Try to DMA map all the blocks... */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov for (pMblk = pTxPkt->pMblk; pMblk; pMblk = pMblk->b_cont)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * The fragment was successfully mapped now move on to the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * next one. Here we set pCopyFrag to NULL which represents
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * a break of continuous data in the copy buffer. If the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * packet header was copied the first fragment points to the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * beginning of the copy buffer. Since this block was mapped
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * any future blocks that have to be copied must be handled by
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * a new fragment even though the fragment is pointed to the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * copied data in the copy buffer.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * The frament was not mapped or was partially mapped. In
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * either case we will no longer try to map the remaining
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * blocks. All remaining packet data is copied.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov msgSize = MBLKL(pMblk); /* new msgSize with partial binding */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* remaining packet is too large (length more than copy buffer) */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ASSERT((copySize + msgSize) <= pTxPkt->cbLength);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov bcopy(pMblk->b_rptr, (pTxPkt->pCbBuf + copySize), msgSize);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * If pCopyFrag is already specified then simply update the copy size.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * If not then set pCopyFrag to the next available fragment.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ASSERT((pTxPkt->frag_list.cnt + 1) <= BNXE_MAX_DMA_FRAGS_PER_PKT);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pCopyFrag = &pTxPkt->frag_list.frag_arr[pTxPkt->frag_list.cnt++];
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pCopyFrag->addr.as_u64 = pTxPkt->cbPhysAddr.as_u64 + copySize;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* update count of bytes in the copy buffer needed for DMA sync */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* DMA sync the copy buffer before sending */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov rc = ddi_dma_sync(pTxPkt->cbDmaHandle, 0, copySize,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeCheckDmaHandle(pTxPkt->cbDmaHandle) != DDI_FM_OK)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_DEGRADED);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeLogWarn(pUM, "(%d) Failed to dma sync tx copy (%p / %d)",
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov/* this code is derived from that shown in RFC 1071 Section 4.1 */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* the inner loop */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* add left-over byte, if any */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* fold 32-bit sum to 16 bits */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * Everest1 (i.e. 57710, 57711, 57711E) does not natively support UDP checksums
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * and does not know anything about the UDP header and where the checksum field
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * is located. It only knows about TCP. Therefore we "lie" to the hardware for
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * outgoing UDP packets w/ checksum offload. Since the checksum field offset
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * for TCP is 16 bytes and for UDP it is 6 bytes we pass a pointer to the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * hardware that is 10 bytes less than the start of the UDP header. This allows
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * the hardware to write the checksum in the correct spot. But the hardware
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * will compute a checksum which includes the last 10 bytes of the IP header.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * To correct this we tweak the stack computed pseudo checksum by folding in the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * calculation of the inverse checksum for those final 10 bytes of the IP
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * header. This allows the correct checksum to be computed by the hardware.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov#define UDP_TCP_CS_OFFSET_DIFF (TCP_CS_OFFSET - UDP_CS_OFFSET)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic inline u16_t BnxeUdpPseudoCsum(um_device_t * pUM,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* calc cksum on last UDP_TCP_CS_OFFSET_DIFF bytes of ip header */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov sum16 = BnxeCalcCksum(&pIpHdr[ipHdrLen - UDP_TCP_CS_OFFSET_DIFF],
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* substruct the calculated cksum from the udp pseudo cksum */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* fold 32-bit sum to 16 bits */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic inline u16_t BnxeGetVlanTag(mblk_t * pMblk)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ASSERT(MBLKL(pMblk) >= sizeof(struct ether_vlan_header));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return GLD_VTAG_VID(ntohs(((struct ether_vlan_header *)pMblk->b_rptr)->ether_tci));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic inline int BnxeGetHdrInfo(um_device_t * pUM,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* At least the MAC header... */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeLogWarn(pUM, "Invalid initial segment size in packet!");
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov mac_hcksum_get(pMblk, &csStart, &csStuff, NULL, NULL, &csFlags);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* get the Ethernet header */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* grab the destination mac addr */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov memcpy(pTxPkt->tx_info.dst_mac_addr, pL2Hdr, 6);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.flags |= LM_TX_FLAG_TCP_LSO_FRAME;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.lso_mss = (u16_t)DB_LSOMSS(pMblk);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* no offload requested, just check for VLAN */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (((struct ether_header *)pMblk->b_rptr)->ether_type ==
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.vlan_tag = BnxeGetVlanTag(pMblk);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.flags |= LM_TX_FLAG_VLAN_TAG_EXISTS;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (((struct ether_header *)pL2Hdr)->ether_type == htons(ETHERTYPE_VLAN))
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.vlan_tag = BnxeGetVlanTag(pMblk);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.flags |= LM_TX_FLAG_VLAN_TAG_EXISTS;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.flags |= LM_TX_FLAG_COMPUTE_IP_CKSUM;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.flags |= LM_TX_FLAG_COMPUTE_TCP_UDP_CKSUM;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov l4HdrLen = (l2HdrLen + csStuff + sizeof(u16_t));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * For TCP, here we ignore the urgent pointer and size of the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * options. We'll get that info later.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* Solaris doesn't do LSO if there is option in the IP header. */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov l4HdrLen = (l2HdrLen + l3HdrLen + sizeof(struct tcphdr));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* the header is in the first block */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* the header is in the second block */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pL3Hdr = pMblk->b_cont->b_rptr + (l2HdrLen - msgSize);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* do a pullup to make sure headers are in the first block */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if ((pMblk = msgpullup(pMblk, l4HdrLen)) == NULL)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* must be IPv4 or IPv6 */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe ASSERT((pL3Hdr[0] & 0xf0) == 0x60 || (pL3Hdr[0] & 0xf0) == 0x40);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe pTxPkt->tx_info.flags |= LM_TX_FLAG_IPV6_PACKET;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (lso || ((csStuff - csStart) == TCP_CS_OFFSET))
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* get the TCP header */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.tcp_nonce_sum_bit = (pL4Hdr[12] & 0x1);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe pTxPkt->tx_info.tcp_pseudo_csum = ntohs(*((u16_t *)&pL4Hdr[TCP_CS_OFFSET]));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.lso_ipid = ntohs(*((u16_t *)&pL3Hdr[4]));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.lso_tcp_send_seq = ntohl(*((u32_t *)&pL4Hdr[4]));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* get the UDP header */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe pTxPkt->tx_info.cs_any_offset = UDP_TCP_CS_OFFSET_DIFF;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeUdpPseudoCsum(pUM, pL4Hdr, pL3Hdr, l3HdrLen) :
int idx,
if (!numPkts)
return BNXE_TX_HDWRFULL;
goto BnxeTxSendMblk_fail;
goto BnxeTxSendMblk_fail;
if (numPkts)
return BNXE_TX_GOODXMIT;
return BNXE_TX_GOODXMIT;
return BNXE_TX_DEFERPKT;
return BNXE_TX_GOODXMIT;
int idx)
int cliIdx)
switch (cliIdx)
case LM_CLI_IDX_FCOE:
case LM_CLI_IDX_NDIS:
return NULL;
NULL,
return NULL;
size,
NULL,
&length,
return NULL;
NULL,
NULL,
&cookie,
return NULL;
for (j = 0; j < BNXE_MAX_DMA_HANDLES_PER_PKT; j++)
NULL,
j, rc);
return NULL;
return pTxPkt;
int idx)
sizeof(struct ether_vlan_header)));
sizeof(struct ether_vlan_header)));
int cliIdx)
switch (cliIdx)
case LM_CLI_IDX_FCOE:
case LM_CLI_IDX_NDIS:
return rc;
int idx)
int cliIdx)
switch (cliIdx)
case LM_CLI_IDX_FCOE:
case LM_CLI_IDX_NDIS: