diff options
Diffstat (limited to 'drivers/net/ixgbe/ixgbe_fcoe.c')
-rw-r--r-- | drivers/net/ixgbe/ixgbe_fcoe.c | 836 |
1 files changed, 836 insertions, 0 deletions
diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c new file mode 100644 index 00000000000..824edae7786 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_fcoe.c | |||
@@ -0,0 +1,836 @@ | |||
1 | /******************************************************************************* | ||
2 | |||
3 | Intel 10 Gigabit PCI Express Linux driver | ||
4 | Copyright(c) 1999 - 2011 Intel Corporation. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify it | ||
7 | under the terms and conditions of the GNU General Public License, | ||
8 | version 2, as published by the Free Software Foundation. | ||
9 | |||
10 | This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License along with | ||
16 | this program; if not, write to the Free Software Foundation, Inc., | ||
17 | 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | |||
19 | The full GNU General Public License is included in this distribution in | ||
20 | the file called "COPYING". | ||
21 | |||
22 | Contact Information: | ||
23 | e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||
24 | Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
25 | |||
26 | *******************************************************************************/ | ||
27 | |||
28 | #include "ixgbe.h" | ||
29 | #include <linux/if_ether.h> | ||
30 | #include <linux/gfp.h> | ||
31 | #include <linux/if_vlan.h> | ||
32 | #include <scsi/scsi_cmnd.h> | ||
33 | #include <scsi/scsi_device.h> | ||
34 | #include <scsi/fc/fc_fs.h> | ||
35 | #include <scsi/fc/fc_fcoe.h> | ||
36 | #include <scsi/libfc.h> | ||
37 | #include <scsi/libfcoe.h> | ||
38 | |||
39 | /** | ||
40 | * ixgbe_fcoe_clear_ddp - clear the given ddp context | ||
41 | * @ddp - ptr to the ixgbe_fcoe_ddp | ||
42 | * | ||
43 | * Returns : none | ||
44 | * | ||
45 | */ | ||
46 | static inline void ixgbe_fcoe_clear_ddp(struct ixgbe_fcoe_ddp *ddp) | ||
47 | { | ||
48 | ddp->len = 0; | ||
49 | ddp->err = 1; | ||
50 | ddp->udl = NULL; | ||
51 | ddp->udp = 0UL; | ||
52 | ddp->sgl = NULL; | ||
53 | ddp->sgc = 0; | ||
54 | } | ||
55 | |||
56 | /** | ||
57 | * ixgbe_fcoe_ddp_put - free the ddp context for a given xid | ||
58 | * @netdev: the corresponding net_device | ||
59 | * @xid: the xid that corresponding ddp will be freed | ||
60 | * | ||
61 | * This is the implementation of net_device_ops.ndo_fcoe_ddp_done | ||
62 | * and it is expected to be called by ULD, i.e., FCP layer of libfc | ||
63 | * to release the corresponding ddp context when the I/O is done. | ||
64 | * | ||
65 | * Returns : data length already ddp-ed in bytes | ||
66 | */ | ||
67 | int ixgbe_fcoe_ddp_put(struct net_device *netdev, u16 xid) | ||
68 | { | ||
69 | int len = 0; | ||
70 | struct ixgbe_fcoe *fcoe; | ||
71 | struct ixgbe_adapter *adapter; | ||
72 | struct ixgbe_fcoe_ddp *ddp; | ||
73 | u32 fcbuff; | ||
74 | |||
75 | if (!netdev) | ||
76 | goto out_ddp_put; | ||
77 | |||
78 | if (xid >= IXGBE_FCOE_DDP_MAX) | ||
79 | goto out_ddp_put; | ||
80 | |||
81 | adapter = netdev_priv(netdev); | ||
82 | fcoe = &adapter->fcoe; | ||
83 | ddp = &fcoe->ddp[xid]; | ||
84 | if (!ddp->udl) | ||
85 | goto out_ddp_put; | ||
86 | |||
87 | len = ddp->len; | ||
88 | /* if there an error, force to invalidate ddp context */ | ||
89 | if (ddp->err) { | ||
90 | spin_lock_bh(&fcoe->lock); | ||
91 | IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCFLT, 0); | ||
92 | IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCFLTRW, | ||
93 | (xid | IXGBE_FCFLTRW_WE)); | ||
94 | IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCBUFF, 0); | ||
95 | IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCDMARW, | ||
96 | (xid | IXGBE_FCDMARW_WE)); | ||
97 | |||
98 | /* guaranteed to be invalidated after 100us */ | ||
99 | IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCDMARW, | ||
100 | (xid | IXGBE_FCDMARW_RE)); | ||
101 | fcbuff = IXGBE_READ_REG(&adapter->hw, IXGBE_FCBUFF); | ||
102 | spin_unlock_bh(&fcoe->lock); | ||
103 | if (fcbuff & IXGBE_FCBUFF_VALID) | ||
104 | udelay(100); | ||
105 | } | ||
106 | if (ddp->sgl) | ||
107 | pci_unmap_sg(adapter->pdev, ddp->sgl, ddp->sgc, | ||
108 | DMA_FROM_DEVICE); | ||
109 | if (ddp->pool) { | ||
110 | pci_pool_free(ddp->pool, ddp->udl, ddp->udp); | ||
111 | ddp->pool = NULL; | ||
112 | } | ||
113 | |||
114 | ixgbe_fcoe_clear_ddp(ddp); | ||
115 | |||
116 | out_ddp_put: | ||
117 | return len; | ||
118 | } | ||
119 | |||
120 | /** | ||
121 | * ixgbe_fcoe_ddp_setup - called to set up ddp context | ||
122 | * @netdev: the corresponding net_device | ||
123 | * @xid: the exchange id requesting ddp | ||
124 | * @sgl: the scatter-gather list for this request | ||
125 | * @sgc: the number of scatter-gather items | ||
126 | * | ||
127 | * Returns : 1 for success and 0 for no ddp | ||
128 | */ | ||
129 | static int ixgbe_fcoe_ddp_setup(struct net_device *netdev, u16 xid, | ||
130 | struct scatterlist *sgl, unsigned int sgc, | ||
131 | int target_mode) | ||
132 | { | ||
133 | struct ixgbe_adapter *adapter; | ||
134 | struct ixgbe_hw *hw; | ||
135 | struct ixgbe_fcoe *fcoe; | ||
136 | struct ixgbe_fcoe_ddp *ddp; | ||
137 | struct scatterlist *sg; | ||
138 | unsigned int i, j, dmacount; | ||
139 | unsigned int len; | ||
140 | static const unsigned int bufflen = IXGBE_FCBUFF_MIN; | ||
141 | unsigned int firstoff = 0; | ||
142 | unsigned int lastsize; | ||
143 | unsigned int thisoff = 0; | ||
144 | unsigned int thislen = 0; | ||
145 | u32 fcbuff, fcdmarw, fcfltrw, fcrxctl; | ||
146 | dma_addr_t addr = 0; | ||
147 | struct pci_pool *pool; | ||
148 | |||
149 | if (!netdev || !sgl) | ||
150 | return 0; | ||
151 | |||
152 | adapter = netdev_priv(netdev); | ||
153 | if (xid >= IXGBE_FCOE_DDP_MAX) { | ||
154 | e_warn(drv, "xid=0x%x out-of-range\n", xid); | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | /* no DDP if we are already down or resetting */ | ||
159 | if (test_bit(__IXGBE_DOWN, &adapter->state) || | ||
160 | test_bit(__IXGBE_RESETTING, &adapter->state)) | ||
161 | return 0; | ||
162 | |||
163 | fcoe = &adapter->fcoe; | ||
164 | if (!fcoe->pool) { | ||
165 | e_warn(drv, "xid=0x%x no ddp pool for fcoe\n", xid); | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | ddp = &fcoe->ddp[xid]; | ||
170 | if (ddp->sgl) { | ||
171 | e_err(drv, "xid 0x%x w/ non-null sgl=%p nents=%d\n", | ||
172 | xid, ddp->sgl, ddp->sgc); | ||
173 | return 0; | ||
174 | } | ||
175 | ixgbe_fcoe_clear_ddp(ddp); | ||
176 | |||
177 | /* setup dma from scsi command sgl */ | ||
178 | dmacount = pci_map_sg(adapter->pdev, sgl, sgc, DMA_FROM_DEVICE); | ||
179 | if (dmacount == 0) { | ||
180 | e_err(drv, "xid 0x%x DMA map error\n", xid); | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | /* alloc the udl from per cpu ddp pool */ | ||
185 | pool = *per_cpu_ptr(fcoe->pool, get_cpu()); | ||
186 | ddp->udl = pci_pool_alloc(pool, GFP_ATOMIC, &ddp->udp); | ||
187 | if (!ddp->udl) { | ||
188 | e_err(drv, "failed allocated ddp context\n"); | ||
189 | goto out_noddp_unmap; | ||
190 | } | ||
191 | ddp->pool = pool; | ||
192 | ddp->sgl = sgl; | ||
193 | ddp->sgc = sgc; | ||
194 | |||
195 | j = 0; | ||
196 | for_each_sg(sgl, sg, dmacount, i) { | ||
197 | addr = sg_dma_address(sg); | ||
198 | len = sg_dma_len(sg); | ||
199 | while (len) { | ||
200 | /* max number of buffers allowed in one DDP context */ | ||
201 | if (j >= IXGBE_BUFFCNT_MAX) { | ||
202 | e_err(drv, "xid=%x:%d,%d,%d:addr=%llx " | ||
203 | "not enough descriptors\n", | ||
204 | xid, i, j, dmacount, (u64)addr); | ||
205 | goto out_noddp_free; | ||
206 | } | ||
207 | |||
208 | /* get the offset of length of current buffer */ | ||
209 | thisoff = addr & ((dma_addr_t)bufflen - 1); | ||
210 | thislen = min((bufflen - thisoff), len); | ||
211 | /* | ||
212 | * all but the 1st buffer (j == 0) | ||
213 | * must be aligned on bufflen | ||
214 | */ | ||
215 | if ((j != 0) && (thisoff)) | ||
216 | goto out_noddp_free; | ||
217 | /* | ||
218 | * all but the last buffer | ||
219 | * ((i == (dmacount - 1)) && (thislen == len)) | ||
220 | * must end at bufflen | ||
221 | */ | ||
222 | if (((i != (dmacount - 1)) || (thislen != len)) | ||
223 | && ((thislen + thisoff) != bufflen)) | ||
224 | goto out_noddp_free; | ||
225 | |||
226 | ddp->udl[j] = (u64)(addr - thisoff); | ||
227 | /* only the first buffer may have none-zero offset */ | ||
228 | if (j == 0) | ||
229 | firstoff = thisoff; | ||
230 | len -= thislen; | ||
231 | addr += thislen; | ||
232 | j++; | ||
233 | } | ||
234 | } | ||
235 | /* only the last buffer may have non-full bufflen */ | ||
236 | lastsize = thisoff + thislen; | ||
237 | |||
238 | /* | ||
239 | * lastsize can not be buffer len. | ||
240 | * If it is then adding another buffer with lastsize = 1. | ||
241 | */ | ||
242 | if (lastsize == bufflen) { | ||
243 | if (j >= IXGBE_BUFFCNT_MAX) { | ||
244 | e_err(drv, "xid=%x:%d,%d,%d:addr=%llx " | ||
245 | "not enough user buffers. We need an extra " | ||
246 | "buffer because lastsize is bufflen.\n", | ||
247 | xid, i, j, dmacount, (u64)addr); | ||
248 | goto out_noddp_free; | ||
249 | } | ||
250 | |||
251 | ddp->udl[j] = (u64)(fcoe->extra_ddp_buffer_dma); | ||
252 | j++; | ||
253 | lastsize = 1; | ||
254 | } | ||
255 | put_cpu(); | ||
256 | |||
257 | fcbuff = (IXGBE_FCBUFF_4KB << IXGBE_FCBUFF_BUFFSIZE_SHIFT); | ||
258 | fcbuff |= ((j & 0xff) << IXGBE_FCBUFF_BUFFCNT_SHIFT); | ||
259 | fcbuff |= (firstoff << IXGBE_FCBUFF_OFFSET_SHIFT); | ||
260 | /* Set WRCONTX bit to allow DDP for target */ | ||
261 | if (target_mode) | ||
262 | fcbuff |= (IXGBE_FCBUFF_WRCONTX); | ||
263 | fcbuff |= (IXGBE_FCBUFF_VALID); | ||
264 | |||
265 | fcdmarw = xid; | ||
266 | fcdmarw |= IXGBE_FCDMARW_WE; | ||
267 | fcdmarw |= (lastsize << IXGBE_FCDMARW_LASTSIZE_SHIFT); | ||
268 | |||
269 | fcfltrw = xid; | ||
270 | fcfltrw |= IXGBE_FCFLTRW_WE; | ||
271 | |||
272 | /* program DMA context */ | ||
273 | hw = &adapter->hw; | ||
274 | spin_lock_bh(&fcoe->lock); | ||
275 | |||
276 | /* turn on last frame indication for target mode as FCP_RSPtarget is | ||
277 | * supposed to send FCP_RSP when it is done. */ | ||
278 | if (target_mode && !test_bit(__IXGBE_FCOE_TARGET, &fcoe->mode)) { | ||
279 | set_bit(__IXGBE_FCOE_TARGET, &fcoe->mode); | ||
280 | fcrxctl = IXGBE_READ_REG(hw, IXGBE_FCRXCTRL); | ||
281 | fcrxctl |= IXGBE_FCRXCTRL_LASTSEQH; | ||
282 | IXGBE_WRITE_REG(hw, IXGBE_FCRXCTRL, fcrxctl); | ||
283 | } | ||
284 | |||
285 | IXGBE_WRITE_REG(hw, IXGBE_FCPTRL, ddp->udp & DMA_BIT_MASK(32)); | ||
286 | IXGBE_WRITE_REG(hw, IXGBE_FCPTRH, (u64)ddp->udp >> 32); | ||
287 | IXGBE_WRITE_REG(hw, IXGBE_FCBUFF, fcbuff); | ||
288 | IXGBE_WRITE_REG(hw, IXGBE_FCDMARW, fcdmarw); | ||
289 | /* program filter context */ | ||
290 | IXGBE_WRITE_REG(hw, IXGBE_FCPARAM, 0); | ||
291 | IXGBE_WRITE_REG(hw, IXGBE_FCFLT, IXGBE_FCFLT_VALID); | ||
292 | IXGBE_WRITE_REG(hw, IXGBE_FCFLTRW, fcfltrw); | ||
293 | |||
294 | spin_unlock_bh(&fcoe->lock); | ||
295 | |||
296 | return 1; | ||
297 | |||
298 | out_noddp_free: | ||
299 | pci_pool_free(pool, ddp->udl, ddp->udp); | ||
300 | ixgbe_fcoe_clear_ddp(ddp); | ||
301 | |||
302 | out_noddp_unmap: | ||
303 | pci_unmap_sg(adapter->pdev, sgl, sgc, DMA_FROM_DEVICE); | ||
304 | put_cpu(); | ||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | /** | ||
309 | * ixgbe_fcoe_ddp_get - called to set up ddp context in initiator mode | ||
310 | * @netdev: the corresponding net_device | ||
311 | * @xid: the exchange id requesting ddp | ||
312 | * @sgl: the scatter-gather list for this request | ||
313 | * @sgc: the number of scatter-gather items | ||
314 | * | ||
315 | * This is the implementation of net_device_ops.ndo_fcoe_ddp_setup | ||
316 | * and is expected to be called from ULD, e.g., FCP layer of libfc | ||
317 | * to set up ddp for the corresponding xid of the given sglist for | ||
318 | * the corresponding I/O. | ||
319 | * | ||
320 | * Returns : 1 for success and 0 for no ddp | ||
321 | */ | ||
322 | int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, | ||
323 | struct scatterlist *sgl, unsigned int sgc) | ||
324 | { | ||
325 | return ixgbe_fcoe_ddp_setup(netdev, xid, sgl, sgc, 0); | ||
326 | } | ||
327 | |||
328 | /** | ||
329 | * ixgbe_fcoe_ddp_target - called to set up ddp context in target mode | ||
330 | * @netdev: the corresponding net_device | ||
331 | * @xid: the exchange id requesting ddp | ||
332 | * @sgl: the scatter-gather list for this request | ||
333 | * @sgc: the number of scatter-gather items | ||
334 | * | ||
335 | * This is the implementation of net_device_ops.ndo_fcoe_ddp_target | ||
336 | * and is expected to be called from ULD, e.g., FCP layer of libfc | ||
337 | * to set up ddp for the corresponding xid of the given sglist for | ||
338 | * the corresponding I/O. The DDP in target mode is a write I/O request | ||
339 | * from the initiator. | ||
340 | * | ||
341 | * Returns : 1 for success and 0 for no ddp | ||
342 | */ | ||
343 | int ixgbe_fcoe_ddp_target(struct net_device *netdev, u16 xid, | ||
344 | struct scatterlist *sgl, unsigned int sgc) | ||
345 | { | ||
346 | return ixgbe_fcoe_ddp_setup(netdev, xid, sgl, sgc, 1); | ||
347 | } | ||
348 | |||
349 | /** | ||
350 | * ixgbe_fcoe_ddp - check ddp status and mark it done | ||
351 | * @adapter: ixgbe adapter | ||
352 | * @rx_desc: advanced rx descriptor | ||
353 | * @skb: the skb holding the received data | ||
354 | * | ||
355 | * This checks ddp status. | ||
356 | * | ||
357 | * Returns : < 0 indicates an error or not a FCiE ddp, 0 indicates | ||
358 | * not passing the skb to ULD, > 0 indicates is the length of data | ||
359 | * being ddped. | ||
360 | */ | ||
361 | int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, | ||
362 | union ixgbe_adv_rx_desc *rx_desc, | ||
363 | struct sk_buff *skb, | ||
364 | u32 staterr) | ||
365 | { | ||
366 | u16 xid; | ||
367 | u32 fctl; | ||
368 | u32 fceofe, fcerr, fcstat; | ||
369 | int rc = -EINVAL; | ||
370 | struct ixgbe_fcoe *fcoe; | ||
371 | struct ixgbe_fcoe_ddp *ddp; | ||
372 | struct fc_frame_header *fh; | ||
373 | struct fcoe_crc_eof *crc; | ||
374 | |||
375 | fcerr = (staterr & IXGBE_RXDADV_ERR_FCERR); | ||
376 | fceofe = (staterr & IXGBE_RXDADV_ERR_FCEOFE); | ||
377 | if (fcerr == IXGBE_FCERR_BADCRC) | ||
378 | skb_checksum_none_assert(skb); | ||
379 | else | ||
380 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
381 | |||
382 | if (eth_hdr(skb)->h_proto == htons(ETH_P_8021Q)) | ||
383 | fh = (struct fc_frame_header *)(skb->data + | ||
384 | sizeof(struct vlan_hdr) + sizeof(struct fcoe_hdr)); | ||
385 | else | ||
386 | fh = (struct fc_frame_header *)(skb->data + | ||
387 | sizeof(struct fcoe_hdr)); | ||
388 | fctl = ntoh24(fh->fh_f_ctl); | ||
389 | if (fctl & FC_FC_EX_CTX) | ||
390 | xid = be16_to_cpu(fh->fh_ox_id); | ||
391 | else | ||
392 | xid = be16_to_cpu(fh->fh_rx_id); | ||
393 | |||
394 | if (xid >= IXGBE_FCOE_DDP_MAX) | ||
395 | goto ddp_out; | ||
396 | |||
397 | fcoe = &adapter->fcoe; | ||
398 | ddp = &fcoe->ddp[xid]; | ||
399 | if (!ddp->udl) | ||
400 | goto ddp_out; | ||
401 | |||
402 | if (fcerr | fceofe) | ||
403 | goto ddp_out; | ||
404 | |||
405 | fcstat = (staterr & IXGBE_RXDADV_STAT_FCSTAT); | ||
406 | if (fcstat) { | ||
407 | /* update length of DDPed data */ | ||
408 | ddp->len = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); | ||
409 | /* unmap the sg list when FCP_RSP is received */ | ||
410 | if (fcstat == IXGBE_RXDADV_STAT_FCSTAT_FCPRSP) { | ||
411 | pci_unmap_sg(adapter->pdev, ddp->sgl, | ||
412 | ddp->sgc, DMA_FROM_DEVICE); | ||
413 | ddp->err = (fcerr | fceofe); | ||
414 | ddp->sgl = NULL; | ||
415 | ddp->sgc = 0; | ||
416 | } | ||
417 | /* return 0 to bypass going to ULD for DDPed data */ | ||
418 | if (fcstat == IXGBE_RXDADV_STAT_FCSTAT_DDP) | ||
419 | rc = 0; | ||
420 | else if (ddp->len) | ||
421 | rc = ddp->len; | ||
422 | } | ||
423 | /* In target mode, check the last data frame of the sequence. | ||
424 | * For DDP in target mode, data is already DDPed but the header | ||
425 | * indication of the last data frame ould allow is to tell if we | ||
426 | * got all the data and the ULP can send FCP_RSP back, as this is | ||
427 | * not a full fcoe frame, we fill the trailer here so it won't be | ||
428 | * dropped by the ULP stack. | ||
429 | */ | ||
430 | if ((fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA) && | ||
431 | (fctl & FC_FC_END_SEQ)) { | ||
432 | crc = (struct fcoe_crc_eof *)skb_put(skb, sizeof(*crc)); | ||
433 | crc->fcoe_eof = FC_EOF_T; | ||
434 | } | ||
435 | ddp_out: | ||
436 | return rc; | ||
437 | } | ||
438 | |||
439 | /** | ||
440 | * ixgbe_fso - ixgbe FCoE Sequence Offload (FSO) | ||
441 | * @adapter: ixgbe adapter | ||
442 | * @tx_ring: tx desc ring | ||
443 | * @skb: associated skb | ||
444 | * @tx_flags: tx flags | ||
445 | * @hdr_len: hdr_len to be returned | ||
446 | * | ||
447 | * This sets up large send offload for FCoE | ||
448 | * | ||
449 | * Returns : 0 indicates no FSO, > 0 for FSO, < 0 for error | ||
450 | */ | ||
451 | int ixgbe_fso(struct ixgbe_ring *tx_ring, struct sk_buff *skb, | ||
452 | u32 tx_flags, u8 *hdr_len) | ||
453 | { | ||
454 | struct fc_frame_header *fh; | ||
455 | u32 vlan_macip_lens; | ||
456 | u32 fcoe_sof_eof = 0; | ||
457 | u32 mss_l4len_idx; | ||
458 | u8 sof, eof; | ||
459 | |||
460 | if (skb_is_gso(skb) && (skb_shinfo(skb)->gso_type != SKB_GSO_FCOE)) { | ||
461 | dev_err(tx_ring->dev, "Wrong gso type %d:expecting SKB_GSO_FCOE\n", | ||
462 | skb_shinfo(skb)->gso_type); | ||
463 | return -EINVAL; | ||
464 | } | ||
465 | |||
466 | /* resets the header to point fcoe/fc */ | ||
467 | skb_set_network_header(skb, skb->mac_len); | ||
468 | skb_set_transport_header(skb, skb->mac_len + | ||
469 | sizeof(struct fcoe_hdr)); | ||
470 | |||
471 | /* sets up SOF and ORIS */ | ||
472 | sof = ((struct fcoe_hdr *)skb_network_header(skb))->fcoe_sof; | ||
473 | switch (sof) { | ||
474 | case FC_SOF_I2: | ||
475 | fcoe_sof_eof = IXGBE_ADVTXD_FCOEF_ORIS; | ||
476 | break; | ||
477 | case FC_SOF_I3: | ||
478 | fcoe_sof_eof = IXGBE_ADVTXD_FCOEF_SOF | | ||
479 | IXGBE_ADVTXD_FCOEF_ORIS; | ||
480 | break; | ||
481 | case FC_SOF_N2: | ||
482 | break; | ||
483 | case FC_SOF_N3: | ||
484 | fcoe_sof_eof = IXGBE_ADVTXD_FCOEF_SOF; | ||
485 | break; | ||
486 | default: | ||
487 | dev_warn(tx_ring->dev, "unknown sof = 0x%x\n", sof); | ||
488 | return -EINVAL; | ||
489 | } | ||
490 | |||
491 | /* the first byte of the last dword is EOF */ | ||
492 | skb_copy_bits(skb, skb->len - 4, &eof, 1); | ||
493 | /* sets up EOF and ORIE */ | ||
494 | switch (eof) { | ||
495 | case FC_EOF_N: | ||
496 | fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_N; | ||
497 | break; | ||
498 | case FC_EOF_T: | ||
499 | /* lso needs ORIE */ | ||
500 | if (skb_is_gso(skb)) | ||
501 | fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_N | | ||
502 | IXGBE_ADVTXD_FCOEF_ORIE; | ||
503 | else | ||
504 | fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_T; | ||
505 | break; | ||
506 | case FC_EOF_NI: | ||
507 | fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_NI; | ||
508 | break; | ||
509 | case FC_EOF_A: | ||
510 | fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_A; | ||
511 | break; | ||
512 | default: | ||
513 | dev_warn(tx_ring->dev, "unknown eof = 0x%x\n", eof); | ||
514 | return -EINVAL; | ||
515 | } | ||
516 | |||
517 | /* sets up PARINC indicating data offset */ | ||
518 | fh = (struct fc_frame_header *)skb_transport_header(skb); | ||
519 | if (fh->fh_f_ctl[2] & FC_FC_REL_OFF) | ||
520 | fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_PARINC; | ||
521 | |||
522 | /* include trailer in headlen as it is replicated per frame */ | ||
523 | *hdr_len = sizeof(struct fcoe_crc_eof); | ||
524 | |||
525 | /* hdr_len includes fc_hdr if FCoE LSO is enabled */ | ||
526 | if (skb_is_gso(skb)) | ||
527 | *hdr_len += (skb_transport_offset(skb) + | ||
528 | sizeof(struct fc_frame_header)); | ||
529 | |||
530 | /* mss_l4len_id: use 1 for FSO as TSO, no need for L4LEN */ | ||
531 | mss_l4len_idx = skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT; | ||
532 | mss_l4len_idx |= 1 << IXGBE_ADVTXD_IDX_SHIFT; | ||
533 | |||
534 | /* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */ | ||
535 | vlan_macip_lens = skb_transport_offset(skb) + | ||
536 | sizeof(struct fc_frame_header); | ||
537 | vlan_macip_lens |= (skb_transport_offset(skb) - 4) | ||
538 | << IXGBE_ADVTXD_MACLEN_SHIFT; | ||
539 | vlan_macip_lens |= tx_flags & IXGBE_TX_FLAGS_VLAN_MASK; | ||
540 | |||
541 | /* write context desc */ | ||
542 | ixgbe_tx_ctxtdesc(tx_ring, vlan_macip_lens, fcoe_sof_eof, | ||
543 | IXGBE_ADVTXT_TUCMD_FCOE, mss_l4len_idx); | ||
544 | |||
545 | return skb_is_gso(skb); | ||
546 | } | ||
547 | |||
548 | static void ixgbe_fcoe_ddp_pools_free(struct ixgbe_fcoe *fcoe) | ||
549 | { | ||
550 | unsigned int cpu; | ||
551 | struct pci_pool **pool; | ||
552 | |||
553 | for_each_possible_cpu(cpu) { | ||
554 | pool = per_cpu_ptr(fcoe->pool, cpu); | ||
555 | if (*pool) | ||
556 | pci_pool_destroy(*pool); | ||
557 | } | ||
558 | free_percpu(fcoe->pool); | ||
559 | fcoe->pool = NULL; | ||
560 | } | ||
561 | |||
562 | static void ixgbe_fcoe_ddp_pools_alloc(struct ixgbe_adapter *adapter) | ||
563 | { | ||
564 | struct ixgbe_fcoe *fcoe = &adapter->fcoe; | ||
565 | unsigned int cpu; | ||
566 | struct pci_pool **pool; | ||
567 | char pool_name[32]; | ||
568 | |||
569 | fcoe->pool = alloc_percpu(struct pci_pool *); | ||
570 | if (!fcoe->pool) | ||
571 | return; | ||
572 | |||
573 | /* allocate pci pool for each cpu */ | ||
574 | for_each_possible_cpu(cpu) { | ||
575 | snprintf(pool_name, 32, "ixgbe_fcoe_ddp_%d", cpu); | ||
576 | pool = per_cpu_ptr(fcoe->pool, cpu); | ||
577 | *pool = pci_pool_create(pool_name, | ||
578 | adapter->pdev, IXGBE_FCPTR_MAX, | ||
579 | IXGBE_FCPTR_ALIGN, PAGE_SIZE); | ||
580 | if (!*pool) { | ||
581 | e_err(drv, "failed to alloc DDP pool on cpu:%d\n", cpu); | ||
582 | ixgbe_fcoe_ddp_pools_free(fcoe); | ||
583 | return; | ||
584 | } | ||
585 | } | ||
586 | } | ||
587 | |||
588 | /** | ||
589 | * ixgbe_configure_fcoe - configures registers for fcoe at start | ||
590 | * @adapter: ptr to ixgbe adapter | ||
591 | * | ||
592 | * This sets up FCoE related registers | ||
593 | * | ||
594 | * Returns : none | ||
595 | */ | ||
596 | void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) | ||
597 | { | ||
598 | int i, fcoe_q, fcoe_i; | ||
599 | struct ixgbe_hw *hw = &adapter->hw; | ||
600 | struct ixgbe_fcoe *fcoe = &adapter->fcoe; | ||
601 | struct ixgbe_ring_feature *f = &adapter->ring_feature[RING_F_FCOE]; | ||
602 | |||
603 | if (!fcoe->pool) { | ||
604 | spin_lock_init(&fcoe->lock); | ||
605 | |||
606 | ixgbe_fcoe_ddp_pools_alloc(adapter); | ||
607 | if (!fcoe->pool) { | ||
608 | e_err(drv, "failed to alloc percpu fcoe DDP pools\n"); | ||
609 | return; | ||
610 | } | ||
611 | |||
612 | /* Extra buffer to be shared by all DDPs for HW work around */ | ||
613 | fcoe->extra_ddp_buffer = kmalloc(IXGBE_FCBUFF_MIN, GFP_ATOMIC); | ||
614 | if (fcoe->extra_ddp_buffer == NULL) { | ||
615 | e_err(drv, "failed to allocated extra DDP buffer\n"); | ||
616 | goto out_ddp_pools; | ||
617 | } | ||
618 | |||
619 | fcoe->extra_ddp_buffer_dma = | ||
620 | dma_map_single(&adapter->pdev->dev, | ||
621 | fcoe->extra_ddp_buffer, | ||
622 | IXGBE_FCBUFF_MIN, | ||
623 | DMA_FROM_DEVICE); | ||
624 | if (dma_mapping_error(&adapter->pdev->dev, | ||
625 | fcoe->extra_ddp_buffer_dma)) { | ||
626 | e_err(drv, "failed to map extra DDP buffer\n"); | ||
627 | goto out_extra_ddp_buffer; | ||
628 | } | ||
629 | } | ||
630 | |||
631 | /* Enable L2 eth type filter for FCoE */ | ||
632 | IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FCOE), | ||
633 | (ETH_P_FCOE | IXGBE_ETQF_FCOE | IXGBE_ETQF_FILTER_EN)); | ||
634 | /* Enable L2 eth type filter for FIP */ | ||
635 | IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FIP), | ||
636 | (ETH_P_FIP | IXGBE_ETQF_FILTER_EN)); | ||
637 | if (adapter->ring_feature[RING_F_FCOE].indices) { | ||
638 | /* Use multiple rx queues for FCoE by redirection table */ | ||
639 | for (i = 0; i < IXGBE_FCRETA_SIZE; i++) { | ||
640 | fcoe_i = f->mask + i % f->indices; | ||
641 | fcoe_i &= IXGBE_FCRETA_ENTRY_MASK; | ||
642 | fcoe_q = adapter->rx_ring[fcoe_i]->reg_idx; | ||
643 | IXGBE_WRITE_REG(hw, IXGBE_FCRETA(i), fcoe_q); | ||
644 | } | ||
645 | IXGBE_WRITE_REG(hw, IXGBE_FCRECTL, IXGBE_FCRECTL_ENA); | ||
646 | IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FCOE), 0); | ||
647 | } else { | ||
648 | /* Use single rx queue for FCoE */ | ||
649 | fcoe_i = f->mask; | ||
650 | fcoe_q = adapter->rx_ring[fcoe_i]->reg_idx; | ||
651 | IXGBE_WRITE_REG(hw, IXGBE_FCRECTL, 0); | ||
652 | IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FCOE), | ||
653 | IXGBE_ETQS_QUEUE_EN | | ||
654 | (fcoe_q << IXGBE_ETQS_RX_QUEUE_SHIFT)); | ||
655 | } | ||
656 | /* send FIP frames to the first FCoE queue */ | ||
657 | fcoe_i = f->mask; | ||
658 | fcoe_q = adapter->rx_ring[fcoe_i]->reg_idx; | ||
659 | IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FIP), | ||
660 | IXGBE_ETQS_QUEUE_EN | | ||
661 | (fcoe_q << IXGBE_ETQS_RX_QUEUE_SHIFT)); | ||
662 | |||
663 | IXGBE_WRITE_REG(hw, IXGBE_FCRXCTRL, | ||
664 | IXGBE_FCRXCTRL_FCOELLI | | ||
665 | IXGBE_FCRXCTRL_FCCRCBO | | ||
666 | (FC_FCOE_VER << IXGBE_FCRXCTRL_FCOEVER_SHIFT)); | ||
667 | return; | ||
668 | |||
669 | out_extra_ddp_buffer: | ||
670 | kfree(fcoe->extra_ddp_buffer); | ||
671 | out_ddp_pools: | ||
672 | ixgbe_fcoe_ddp_pools_free(fcoe); | ||
673 | } | ||
674 | |||
675 | /** | ||
676 | * ixgbe_cleanup_fcoe - release all fcoe ddp context resources | ||
677 | * @adapter : ixgbe adapter | ||
678 | * | ||
679 | * Cleans up outstanding ddp context resources | ||
680 | * | ||
681 | * Returns : none | ||
682 | */ | ||
683 | void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter) | ||
684 | { | ||
685 | int i; | ||
686 | struct ixgbe_fcoe *fcoe = &adapter->fcoe; | ||
687 | |||
688 | if (!fcoe->pool) | ||
689 | return; | ||
690 | |||
691 | for (i = 0; i < IXGBE_FCOE_DDP_MAX; i++) | ||
692 | ixgbe_fcoe_ddp_put(adapter->netdev, i); | ||
693 | dma_unmap_single(&adapter->pdev->dev, | ||
694 | fcoe->extra_ddp_buffer_dma, | ||
695 | IXGBE_FCBUFF_MIN, | ||
696 | DMA_FROM_DEVICE); | ||
697 | kfree(fcoe->extra_ddp_buffer); | ||
698 | ixgbe_fcoe_ddp_pools_free(fcoe); | ||
699 | } | ||
700 | |||
701 | /** | ||
702 | * ixgbe_fcoe_enable - turn on FCoE offload feature | ||
703 | * @netdev: the corresponding netdev | ||
704 | * | ||
705 | * Turns on FCoE offload feature in 82599. | ||
706 | * | ||
707 | * Returns : 0 indicates success or -EINVAL on failure | ||
708 | */ | ||
709 | int ixgbe_fcoe_enable(struct net_device *netdev) | ||
710 | { | ||
711 | int rc = -EINVAL; | ||
712 | struct ixgbe_adapter *adapter = netdev_priv(netdev); | ||
713 | struct ixgbe_fcoe *fcoe = &adapter->fcoe; | ||
714 | |||
715 | |||
716 | if (!(adapter->flags & IXGBE_FLAG_FCOE_CAPABLE)) | ||
717 | goto out_enable; | ||
718 | |||
719 | atomic_inc(&fcoe->refcnt); | ||
720 | if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) | ||
721 | goto out_enable; | ||
722 | |||
723 | e_info(drv, "Enabling FCoE offload features.\n"); | ||
724 | if (netif_running(netdev)) | ||
725 | netdev->netdev_ops->ndo_stop(netdev); | ||
726 | |||
727 | ixgbe_clear_interrupt_scheme(adapter); | ||
728 | |||
729 | adapter->flags |= IXGBE_FLAG_FCOE_ENABLED; | ||
730 | adapter->ring_feature[RING_F_FCOE].indices = IXGBE_FCRETA_SIZE; | ||
731 | netdev->features |= NETIF_F_FCOE_CRC; | ||
732 | netdev->features |= NETIF_F_FSO; | ||
733 | netdev->features |= NETIF_F_FCOE_MTU; | ||
734 | netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1; | ||
735 | |||
736 | ixgbe_init_interrupt_scheme(adapter); | ||
737 | netdev_features_change(netdev); | ||
738 | |||
739 | if (netif_running(netdev)) | ||
740 | netdev->netdev_ops->ndo_open(netdev); | ||
741 | rc = 0; | ||
742 | |||
743 | out_enable: | ||
744 | return rc; | ||
745 | } | ||
746 | |||
747 | /** | ||
748 | * ixgbe_fcoe_disable - turn off FCoE offload feature | ||
749 | * @netdev: the corresponding netdev | ||
750 | * | ||
751 | * Turns off FCoE offload feature in 82599. | ||
752 | * | ||
753 | * Returns : 0 indicates success or -EINVAL on failure | ||
754 | */ | ||
755 | int ixgbe_fcoe_disable(struct net_device *netdev) | ||
756 | { | ||
757 | int rc = -EINVAL; | ||
758 | struct ixgbe_adapter *adapter = netdev_priv(netdev); | ||
759 | struct ixgbe_fcoe *fcoe = &adapter->fcoe; | ||
760 | |||
761 | if (!(adapter->flags & IXGBE_FLAG_FCOE_CAPABLE)) | ||
762 | goto out_disable; | ||
763 | |||
764 | if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) | ||
765 | goto out_disable; | ||
766 | |||
767 | if (!atomic_dec_and_test(&fcoe->refcnt)) | ||
768 | goto out_disable; | ||
769 | |||
770 | e_info(drv, "Disabling FCoE offload features.\n"); | ||
771 | netdev->features &= ~NETIF_F_FCOE_CRC; | ||
772 | netdev->features &= ~NETIF_F_FSO; | ||
773 | netdev->features &= ~NETIF_F_FCOE_MTU; | ||
774 | netdev->fcoe_ddp_xid = 0; | ||
775 | netdev_features_change(netdev); | ||
776 | |||
777 | if (netif_running(netdev)) | ||
778 | netdev->netdev_ops->ndo_stop(netdev); | ||
779 | |||
780 | ixgbe_clear_interrupt_scheme(adapter); | ||
781 | adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED; | ||
782 | adapter->ring_feature[RING_F_FCOE].indices = 0; | ||
783 | ixgbe_cleanup_fcoe(adapter); | ||
784 | ixgbe_init_interrupt_scheme(adapter); | ||
785 | |||
786 | if (netif_running(netdev)) | ||
787 | netdev->netdev_ops->ndo_open(netdev); | ||
788 | rc = 0; | ||
789 | |||
790 | out_disable: | ||
791 | return rc; | ||
792 | } | ||
793 | |||
794 | /** | ||
795 | * ixgbe_fcoe_get_wwn - get world wide name for the node or the port | ||
796 | * @netdev : ixgbe adapter | ||
797 | * @wwn : the world wide name | ||
798 | * @type: the type of world wide name | ||
799 | * | ||
800 | * Returns the node or port world wide name if both the prefix and the san | ||
801 | * mac address are valid, then the wwn is formed based on the NAA-2 for | ||
802 | * IEEE Extended name identifier (ref. to T10 FC-LS Spec., Sec. 15.3). | ||
803 | * | ||
804 | * Returns : 0 on success | ||
805 | */ | ||
806 | int ixgbe_fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type) | ||
807 | { | ||
808 | int rc = -EINVAL; | ||
809 | u16 prefix = 0xffff; | ||
810 | struct ixgbe_adapter *adapter = netdev_priv(netdev); | ||
811 | struct ixgbe_mac_info *mac = &adapter->hw.mac; | ||
812 | |||
813 | switch (type) { | ||
814 | case NETDEV_FCOE_WWNN: | ||
815 | prefix = mac->wwnn_prefix; | ||
816 | break; | ||
817 | case NETDEV_FCOE_WWPN: | ||
818 | prefix = mac->wwpn_prefix; | ||
819 | break; | ||
820 | default: | ||
821 | break; | ||
822 | } | ||
823 | |||
824 | if ((prefix != 0xffff) && | ||
825 | is_valid_ether_addr(mac->san_addr)) { | ||
826 | *wwn = ((u64) prefix << 48) | | ||
827 | ((u64) mac->san_addr[0] << 40) | | ||
828 | ((u64) mac->san_addr[1] << 32) | | ||
829 | ((u64) mac->san_addr[2] << 24) | | ||
830 | ((u64) mac->san_addr[3] << 16) | | ||
831 | ((u64) mac->san_addr[4] << 8) | | ||
832 | ((u64) mac->san_addr[5]); | ||
833 | rc = 0; | ||
834 | } | ||
835 | return rc; | ||
836 | } | ||