/*******************************************************************************
*
* Intel Ethernet Controller XL710 Family Linux Driver
* Copyright(c) 2013 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#include <linux/if_ether.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/fc/fc_fs.h>
#include <scsi/fc/fc_fip.h>
#include <scsi/fc/fc_fcoe.h>
#include <scsi/libfc.h>
#include <scsi/libfcoe.h>
#include <uapi/linux/dcbnl.h>
#include "i40e.h"
#include "i40e_fcoe.h"
/**
* i40e_rx_is_fcoe - returns true if the rx packet type is FCoE
* @ptype: the packet type field from rx descriptor write-back
**/
static inline bool i40e_rx_is_fcoe(u16 ptype)
{
return (ptype >= I40E_RX_PTYPE_L2_FCOE_PAY3) &&
(ptype <= I40E_RX_PTYPE_L2_FCOE_VFT_FCOTHER);
}
/**
* i40e_fcoe_sof_is_class2 - returns true if this is a FC Class 2 SOF
* @sof: the FCoE start of frame delimiter
**/
static inline bool i40e_fcoe_sof_is_class2(u8 sof)
{
return (sof == FC_SOF_I2) || (sof == FC_SOF_N2);
}
/**
* i40e_fcoe_sof_is_class3 - returns true if this is a FC Class 3 SOF
* @sof: the FCoE start of frame delimiter
**/
static inline bool i40e_fcoe_sof_is_class3(u8 sof)
{
return (sof == FC_SOF_I3) || (sof == FC_SOF_N3);
}
/**
* i40e_fcoe_sof_is_supported - returns true if the FC SOF is supported by HW
* @sof: the input SOF value from the frame
**/
static inline bool i40e_fcoe_sof_is_supported(u8 sof)
{
return i40e_fcoe_sof_is_class2(sof) ||
i40e_fcoe_sof_is_class3(sof);
}
/**
* i40e_fcoe_fc_sof - pull the SOF from FCoE header in the frame
* @skb: the frame whose EOF is to be pulled from
**/
static inline int i40e_fcoe_fc_sof(struct sk_buff *skb, u8 *sof)
{
*sof = ((struct fcoe_hdr *)skb_network_header(skb))->fcoe_sof;
if (!i40e_fcoe_sof_is_supported(*sof))
return -EINVAL;
return 0;
}
/**
* i40e_fcoe_eof_is_supported - returns true if the EOF is supported by HW
* @eof: the input EOF value from the frame
**/
static inline bool i40e_fcoe_eof_is_supported(u8 eof)
{
return (eof == FC_EOF_N) || (eof == FC_EOF_T) ||
(eof == FC_EOF_NI) || (eof == FC_EOF_A);
}
/**
* i40e_fcoe_fc_eof - pull EOF from FCoE trailer in the frame
* @skb: the frame whose EOF is to be pulled from
**/
static inline int i40e_fcoe_fc_eof(struct sk_buff *skb, u8 *eof)
{
/* the first byte of the last dword is EOF */
skb_copy_bits(skb, skb->len - 4, eof, 1);
if (!i40e_fcoe_eof_is_supported(*eof))
return -EINVAL;
return 0;
}
/**
* i40e_fcoe_ctxt_eof - convert input FC EOF for descriptor programming
* @eof: the input eof value from the frame
*
* The FC EOF is converted to the value understood by HW for descriptor
* programming. Never call this w/o calling i40e_fcoe_eof_is_supported()
* first and that already checks for all supported valid eof values.
**/
static inline u32 i40e_fcoe_ctxt_eof(u8 eof)
{
switch (eof) {
case FC_EOF_N:
return I40E_TX_DESC_CMD_L4T_EOFT_EOF_N;
case FC_EOF_T:
return I40E_TX_DESC_CMD_L4T_EOFT_EOF_T;
case FC_EOF_NI:
return I40E_TX_DESC_CMD_L4T_EOFT_EOF_NI;
case FC_EOF_A:
return I40E_TX_DESC_CMD_L4T_EOFT_EOF_A;
default:
/* Supported valid eof shall be already checked by
* calling i40e_fcoe_eof_is_supported() first,
* therefore this default case shall never hit.
*/
WARN_ON(1);
return -EINVAL;
}
}
/**
* i40e_fcoe_xid_is_valid - returns true if the exchange id is valid
* @xid: the exchange id
**/
static inline bool i40e_fcoe_xid_is_valid(u16 xid)
{
return (xid != FC_XID_UNKNOWN) && (xid < I40E_FCOE_DDP_MAX);
}
/**
* i40e_fcoe_ddp_unmap - unmap the mapped sglist associated
* @pf: pointer to PF
* @ddp: sw DDP context
*
* Unmap the scatter-gather list associated with the given SW DDP context
*
* Returns: data length already ddp-ed in bytes
*
**/
static inline void i40e_fcoe_ddp_unmap(struct i40e_pf *pf,
struct i40e_fcoe_ddp *ddp)
{
if (test_and_set_bit(__I40E_FCOE_DDP_UNMAPPED, &ddp->flags))
return;
if (ddp->sgl) {
dma_unmap_sg(&pf->pdev->dev, ddp->sgl, ddp->sgc,
DMA_FROM_DEVICE);
ddp->sgl = NULL;
ddp->sgc = 0;
}
if (ddp->pool) {
dma_pool_free(ddp->pool, ddp->udl, ddp->udp);
ddp->pool = NULL;
}
}
/**
* i40e_fcoe_ddp_clear - clear the given SW DDP context
* @ddp - SW DDP context
**/
static inline void i40e_fcoe_ddp_clear(struct i40e_fcoe_ddp *ddp)
{
memset(ddp, 0, sizeof(struct i40e_fcoe_ddp));
ddp->xid = FC_XID_UNKNOWN;
ddp->flags = __I40E_FCOE_DDP_NONE;
}
/**
* i40e_fcoe_progid_is_fcoe - check if the prog_id is for FCoE
* @id: the prog id for the programming status Rx descriptor write-back
*
|