|
@@ -35,6 +35,138 @@
|
|
|
#include <scsi/libfc.h>
|
|
|
#include <scsi/libfcoe.h>
|
|
|
|
|
|
+/**
|
|
|
+ * ixgbe_fso - ixgbe FCoE Sequence Offload (FSO)
|
|
|
+ * @adapter: ixgbe adapter
|
|
|
+ * @tx_ring: tx desc ring
|
|
|
+ * @skb: associated skb
|
|
|
+ * @tx_flags: tx flags
|
|
|
+ * @hdr_len: hdr_len to be returned
|
|
|
+ *
|
|
|
+ * This sets up large send offload for FCoE
|
|
|
+ *
|
|
|
+ * Returns : 0 indicates no FSO, > 0 for FSO, < 0 for error
|
|
|
+ */
|
|
|
+int ixgbe_fso(struct ixgbe_adapter *adapter,
|
|
|
+ struct ixgbe_ring *tx_ring, struct sk_buff *skb,
|
|
|
+ u32 tx_flags, u8 *hdr_len)
|
|
|
+{
|
|
|
+ u8 sof, eof;
|
|
|
+ u32 vlan_macip_lens;
|
|
|
+ u32 fcoe_sof_eof;
|
|
|
+ u32 type_tucmd;
|
|
|
+ u32 mss_l4len_idx;
|
|
|
+ int mss = 0;
|
|
|
+ unsigned int i;
|
|
|
+ struct ixgbe_tx_buffer *tx_buffer_info;
|
|
|
+ struct ixgbe_adv_tx_context_desc *context_desc;
|
|
|
+ struct fc_frame_header *fh;
|
|
|
+
|
|
|
+ if (skb_is_gso(skb) && (skb_shinfo(skb)->gso_type != SKB_GSO_FCOE)) {
|
|
|
+ DPRINTK(DRV, ERR, "Wrong gso type %d:expecting SKB_GSO_FCOE\n",
|
|
|
+ skb_shinfo(skb)->gso_type);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* resets the header to point fcoe/fc */
|
|
|
+ skb_set_network_header(skb, skb->mac_len);
|
|
|
+ skb_set_transport_header(skb, skb->mac_len +
|
|
|
+ sizeof(struct fcoe_hdr));
|
|
|
+
|
|
|
+ /* sets up SOF and ORIS */
|
|
|
+ fcoe_sof_eof = 0;
|
|
|
+ sof = ((struct fcoe_hdr *)skb_network_header(skb))->fcoe_sof;
|
|
|
+ switch (sof) {
|
|
|
+ case FC_SOF_I2:
|
|
|
+ fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_ORIS;
|
|
|
+ break;
|
|
|
+ case FC_SOF_I3:
|
|
|
+ fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_SOF;
|
|
|
+ fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_ORIS;
|
|
|
+ break;
|
|
|
+ case FC_SOF_N2:
|
|
|
+ break;
|
|
|
+ case FC_SOF_N3:
|
|
|
+ fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_SOF;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ DPRINTK(DRV, WARNING, "unknown sof = 0x%x\n", sof);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* the first byte of the last dword is EOF */
|
|
|
+ skb_copy_bits(skb, skb->len - 4, &eof, 1);
|
|
|
+ /* sets up EOF and ORIE */
|
|
|
+ switch (eof) {
|
|
|
+ case FC_EOF_N:
|
|
|
+ fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_N;
|
|
|
+ break;
|
|
|
+ case FC_EOF_T:
|
|
|
+ /* lso needs ORIE */
|
|
|
+ if (skb_is_gso(skb)) {
|
|
|
+ fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_N;
|
|
|
+ fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_ORIE;
|
|
|
+ } else {
|
|
|
+ fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_T;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case FC_EOF_NI:
|
|
|
+ fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_NI;
|
|
|
+ break;
|
|
|
+ case FC_EOF_A:
|
|
|
+ fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_A;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ DPRINTK(DRV, WARNING, "unknown eof = 0x%x\n", eof);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* sets up PARINC indicating data offset */
|
|
|
+ fh = (struct fc_frame_header *)skb_transport_header(skb);
|
|
|
+ if (fh->fh_f_ctl[2] & FC_FC_REL_OFF)
|
|
|
+ fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_PARINC;
|
|
|
+
|
|
|
+ /* hdr_len includes fc_hdr if FCoE lso is enabled */
|
|
|
+ *hdr_len = sizeof(struct fcoe_crc_eof);
|
|
|
+ if (skb_is_gso(skb))
|
|
|
+ *hdr_len += (skb_transport_offset(skb) +
|
|
|
+ sizeof(struct fc_frame_header));
|
|
|
+ /* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */
|
|
|
+ vlan_macip_lens = (skb_transport_offset(skb) +
|
|
|
+ sizeof(struct fc_frame_header));
|
|
|
+ vlan_macip_lens |= ((skb_transport_offset(skb) - 4)
|
|
|
+ << IXGBE_ADVTXD_MACLEN_SHIFT);
|
|
|
+ vlan_macip_lens |= (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK);
|
|
|
+
|
|
|
+ /* type_tycmd and mss: set TUCMD.FCoE to enable offload */
|
|
|
+ type_tucmd = IXGBE_TXD_CMD_DEXT | IXGBE_ADVTXD_DTYP_CTXT |
|
|
|
+ IXGBE_ADVTXT_TUCMD_FCOE;
|
|
|
+ if (skb_is_gso(skb))
|
|
|
+ mss = skb_shinfo(skb)->gso_size;
|
|
|
+ /* mss_l4len_id: use 1 for FSO as TSO, no need for L4LEN */
|
|
|
+ mss_l4len_idx = (mss << IXGBE_ADVTXD_MSS_SHIFT) |
|
|
|
+ (1 << IXGBE_ADVTXD_IDX_SHIFT);
|
|
|
+
|
|
|
+ /* write context desc */
|
|
|
+ i = tx_ring->next_to_use;
|
|
|
+ context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i);
|
|
|
+ context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
|
|
|
+ context_desc->seqnum_seed = cpu_to_le32(fcoe_sof_eof);
|
|
|
+ context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd);
|
|
|
+ context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx);
|
|
|
+
|
|
|
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
|
|
|
+ tx_buffer_info->time_stamp = jiffies;
|
|
|
+ tx_buffer_info->next_to_watch = i;
|
|
|
+
|
|
|
+ i++;
|
|
|
+ if (i == tx_ring->count)
|
|
|
+ i = 0;
|
|
|
+ tx_ring->next_to_use = i;
|
|
|
+
|
|
|
+ return skb_is_gso(skb);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* ixgbe_configure_fcoe - configures registers for fcoe at start
|
|
|
* @adapter: ptr to ixgbe adapter
|