diff options
Diffstat (limited to 'drivers/net/ixgbe/ixgbe_fcoe.c')
-rw-r--r-- | drivers/net/ixgbe/ixgbe_fcoe.c | 168 |
1 files changed, 166 insertions, 2 deletions
diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index fa9f24e2368..a3c9f99515e 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -27,6 +27,9 @@ #include "ixgbe.h" +#ifdef CONFIG_IXGBE_DCB +#include "ixgbe_dcb_82599.h" +#endif /* CONFIG_IXGBE_DCB */ #include <linux/if_ether.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> @@ -289,6 +292,7 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, struct sk_buff *skb) { u16 xid; + u32 fctl; u32 sterr, fceofe, fcerr, fcstat; int rc = -EINVAL; struct ixgbe_fcoe *fcoe; @@ -309,7 +313,12 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, skb_set_transport_header(skb, skb_network_offset(skb) + sizeof(struct fcoe_hdr)); fh = (struct fc_frame_header *)skb_transport_header(skb); - xid = be16_to_cpu(fh->fh_ox_id); + fctl = ntoh24(fh->fh_f_ctl); + if (fctl & FC_FC_EX_CTX) + xid = be16_to_cpu(fh->fh_ox_id); + else + xid = be16_to_cpu(fh->fh_rx_id); + if (xid >= IXGBE_FCOE_DDP_MAX) goto ddp_out; @@ -336,7 +345,7 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, /* return 0 to bypass going to ULD for DDPed data */ if (fcstat == IXGBE_RXDADV_STAT_FCSTAT_DDP) rc = 0; - else + else if (ddp->len) rc = ddp->len; } @@ -554,3 +563,158 @@ void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter) fcoe->pool = NULL; } } + +/** + * ixgbe_fcoe_enable - turn on FCoE offload feature + * @netdev: the corresponding netdev + * + * Turns on FCoE offload feature in 82599. + * + * Returns : 0 indicates success or -EINVAL on failure + */ +int ixgbe_fcoe_enable(struct net_device *netdev) +{ + int rc = -EINVAL; + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + + if (!(adapter->flags & IXGBE_FLAG_FCOE_CAPABLE)) + goto out_enable; + + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) + goto out_enable; + + DPRINTK(DRV, INFO, "Enabling FCoE offload features.\n"); + if (netif_running(netdev)) + netdev->netdev_ops->ndo_stop(netdev); + + ixgbe_clear_interrupt_scheme(adapter); + + adapter->flags |= IXGBE_FLAG_FCOE_ENABLED; + adapter->ring_feature[RING_F_FCOE].indices = IXGBE_FCRETA_SIZE; + netdev->features |= NETIF_F_FCOE_CRC; + netdev->features |= NETIF_F_FSO; + netdev->features |= NETIF_F_FCOE_MTU; + netdev->vlan_features |= NETIF_F_FCOE_CRC; + netdev->vlan_features |= NETIF_F_FSO; + netdev->vlan_features |= NETIF_F_FCOE_MTU; + netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1; + netdev_features_change(netdev); + + ixgbe_init_interrupt_scheme(adapter); + + if (netif_running(netdev)) + netdev->netdev_ops->ndo_open(netdev); + rc = 0; + +out_enable: + return rc; +} + +/** + * ixgbe_fcoe_disable - turn off FCoE offload feature + * @netdev: the corresponding netdev + * + * Turns off FCoE offload feature in 82599. + * + * Returns : 0 indicates success or -EINVAL on failure + */ +int ixgbe_fcoe_disable(struct net_device *netdev) +{ + int rc = -EINVAL; + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + if (!(adapter->flags & IXGBE_FLAG_FCOE_CAPABLE)) + goto out_disable; + + if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) + goto out_disable; + + DPRINTK(DRV, INFO, "Disabling FCoE offload features.\n"); + if (netif_running(netdev)) + netdev->netdev_ops->ndo_stop(netdev); + + ixgbe_clear_interrupt_scheme(adapter); + + adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED; + adapter->ring_feature[RING_F_FCOE].indices = 0; + netdev->features &= ~NETIF_F_FCOE_CRC; + netdev->features &= ~NETIF_F_FSO; + netdev->features &= ~NETIF_F_FCOE_MTU; + netdev->vlan_features &= ~NETIF_F_FCOE_CRC; + netdev->vlan_features &= ~NETIF_F_FSO; + netdev->vlan_features &= ~NETIF_F_FCOE_MTU; + netdev->fcoe_ddp_xid = 0; + netdev_features_change(netdev); + + ixgbe_cleanup_fcoe(adapter); + + ixgbe_init_interrupt_scheme(adapter); + if (netif_running(netdev)) + netdev->netdev_ops->ndo_open(netdev); + rc = 0; + +out_disable: + return rc; +} + +#ifdef CONFIG_IXGBE_DCB +/** + * ixgbe_fcoe_getapp - retrieves current user priority bitmap for FCoE + * @adapter : ixgbe adapter + * + * Finds out the corresponding user priority bitmap from the current + * traffic class that FCoE belongs to. Returns 0 as the invalid user + * priority bitmap to indicate an error. + * + * Returns : 802.1p user priority bitmap for FCoE + */ +u8 ixgbe_fcoe_getapp(struct ixgbe_adapter *adapter) +{ + int i; + u8 tc; + u32 up2tc; + + up2tc = IXGBE_READ_REG(&adapter->hw, IXGBE_RTTUP2TC); + for (i = 0; i < MAX_USER_PRIORITY; i++) { + tc = (u8)(up2tc >> (i * IXGBE_RTTUP2TC_UP_SHIFT)); + tc &= (MAX_TRAFFIC_CLASS - 1); + if (adapter->fcoe.tc == tc) + return 1 << i; + } + + return 0; +} + +/** + * ixgbe_fcoe_setapp - sets the user priority bitmap for FCoE + * @adapter : ixgbe adapter + * @up : 802.1p user priority bitmap + * + * Finds out the traffic class from the input user priority + * bitmap for FCoE. + * + * Returns : 0 on success otherwise returns 1 on error + */ +u8 ixgbe_fcoe_setapp(struct ixgbe_adapter *adapter, u8 up) +{ + int i; + u32 up2tc; + + /* valid user priority bitmap must not be 0 */ + if (up) { + /* from user priority to the corresponding traffic class */ + up2tc = IXGBE_READ_REG(&adapter->hw, IXGBE_RTTUP2TC); + for (i = 0; i < MAX_USER_PRIORITY; i++) { + if (up & (1 << i)) { + up2tc >>= (i * IXGBE_RTTUP2TC_UP_SHIFT); + up2tc &= (MAX_TRAFFIC_CLASS - 1); + adapter->fcoe.tc = (u8)up2tc; + return 0; + } + } + } + + return 1; +} +#endif /* CONFIG_IXGBE_DCB */ |