15df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar/*
25df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
35df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
45df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar *
55df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar * This program is free software; you may redistribute it and/or modify
65df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar * it under the terms of the GNU General Public License as published by
75df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar * the Free Software Foundation; version 2 of the License.
85df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar *
95df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
105df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
115df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
125df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
135df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
145df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
155df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
165df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar * SOFTWARE.
175df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar */
185df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar#include <linux/errno.h>
195df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar#include <linux/pci.h>
205a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
215df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar#include <linux/skbuff.h>
225df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar#include <linux/interrupt.h>
235df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar#include <linux/spinlock.h>
245df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar#include <linux/if_ether.h>
255df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar#include <linux/if_vlan.h>
265df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar#include <linux/workqueue.h>
2778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt#include <scsi/fc/fc_fip.h>
285df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar#include <scsi/fc/fc_els.h>
295df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar#include <scsi/fc/fc_fcoe.h>
305df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar#include <scsi/fc_frame.h>
315df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar#include <scsi/libfc.h>
325df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar#include "fnic_io.h"
335df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar#include "fnic.h"
345df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar#include "cq_enet_desc.h"
355df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar#include "cq_exch_desc.h"
365df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
375df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekarstruct workqueue_struct *fnic_event_queue;
385df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
3978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholtstatic void fnic_set_eth_mode(struct fnic *);
4078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt
415df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekarvoid fnic_handle_link(struct work_struct *work)
425df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar{
435df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fnic *fnic = container_of(work, struct fnic, link_work);
445df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	unsigned long flags;
455df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	int old_link_status;
465df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	u32 old_link_down_cnt;
475df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
485df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	spin_lock_irqsave(&fnic->fnic_lock, flags);
495df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
505df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	if (fnic->stop_rx_link_events) {
515df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
525df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		return;
535df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	}
545df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
555df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	old_link_down_cnt = fnic->link_down_cnt;
565df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	old_link_status = fnic->link_status;
575df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	fnic->link_status = vnic_dev_link_status(fnic->vdev);
585df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	fnic->link_down_cnt = vnic_dev_link_down_cnt(fnic->vdev);
595df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
605df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	if (old_link_status == fnic->link_status) {
615df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		if (!fnic->link_status)
625df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			/* DOWN -> DOWN */
635df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			spin_unlock_irqrestore(&fnic->fnic_lock, flags);
645df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		else {
655df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			if (old_link_down_cnt != fnic->link_down_cnt) {
665df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				/* UP -> DOWN -> UP */
675df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				fnic->lport->host_stats.link_failure_count++;
685df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				spin_unlock_irqrestore(&fnic->fnic_lock, flags);
695df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host,
705df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar					     "link down\n");
7178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt				fcoe_ctlr_link_down(&fnic->ctlr);
725df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host,
735df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar					     "link up\n");
7478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt				fcoe_ctlr_link_up(&fnic->ctlr);
755df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			} else
765df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				/* UP -> UP */
775df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				spin_unlock_irqrestore(&fnic->fnic_lock, flags);
785df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		}
795df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	} else if (fnic->link_status) {
805df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		/* DOWN -> UP */
815df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
825df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, "link up\n");
8378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		fcoe_ctlr_link_up(&fnic->ctlr);
845df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	} else {
855df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		/* UP -> DOWN */
865df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		fnic->lport->host_stats.link_failure_count++;
875df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
885df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, "link down\n");
8978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		fcoe_ctlr_link_down(&fnic->ctlr);
905df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	}
915df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
925df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar}
935df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
945df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar/*
955df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar * This function passes incoming fabric frames to libFC
965df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar */
975df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekarvoid fnic_handle_frame(struct work_struct *work)
985df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar{
995df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fnic *fnic = container_of(work, struct fnic, frame_work);
1005df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fc_lport *lp = fnic->lport;
1015df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	unsigned long flags;
1025df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct sk_buff *skb;
1035df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fc_frame *fp;
1045df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
1055df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	while ((skb = skb_dequeue(&fnic->frame_queue))) {
1065df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
1075df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		spin_lock_irqsave(&fnic->fnic_lock, flags);
1085df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		if (fnic->stop_rx_link_events) {
1095df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			spin_unlock_irqrestore(&fnic->fnic_lock, flags);
1105df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			dev_kfree_skb(skb);
1115df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			return;
1125df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		}
1135df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		fp = (struct fc_frame *)skb;
11478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt
11578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		/*
11678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		 * If we're in a transitional state, just re-queue and return.
11778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		 * The queue will be serviced when we get to a stable state.
11878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		 */
11978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		if (fnic->state != FNIC_IN_FC_MODE &&
12078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		    fnic->state != FNIC_IN_ETH_MODE) {
12178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt			skb_queue_head(&fnic->frame_queue, skb);
12278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt			spin_unlock_irqrestore(&fnic->fnic_lock, flags);
12378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt			return;
1245df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		}
1255df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
1265df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
12752ff878c912215210f53c0a080552dd6ba3055a2Vasu Dev		fc_exch_recv(lp, fp);
1285df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	}
1295df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar}
1305df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
13178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt/**
13278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * fnic_import_rq_eth_pkt() - handle received FCoE or FIP frame.
13378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * @fnic:	fnic instance.
13478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * @skb:	Ethernet Frame.
13578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt */
13678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholtstatic inline int fnic_import_rq_eth_pkt(struct fnic *fnic, struct sk_buff *skb)
1375df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar{
1385df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fc_frame *fp;
1395df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct ethhdr *eh;
1405df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fcoe_hdr *fcoe_hdr;
1415df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fcoe_crc_eof *ft;
1425df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
14378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	/*
14478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	 * Undo VLAN encapsulation if present.
14578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	 */
1465df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	eh = (struct ethhdr *)skb->data;
14778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	if (eh->h_proto == htons(ETH_P_8021Q)) {
14878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		memmove((u8 *)eh + VLAN_HLEN, eh, ETH_ALEN * 2);
14978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		eh = (struct ethhdr *)skb_pull(skb, VLAN_HLEN);
15078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		skb_reset_mac_header(skb);
15178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	}
15278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	if (eh->h_proto == htons(ETH_P_FIP)) {
15378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		skb_pull(skb, sizeof(*eh));
15478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		fcoe_ctlr_recv(&fnic->ctlr, skb);
15578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		return 1;		/* let caller know packet was used */
15678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	}
15778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	if (eh->h_proto != htons(ETH_P_FCOE))
15878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		goto drop;
15978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	skb_set_network_header(skb, sizeof(*eh));
16078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	skb_pull(skb, sizeof(*eh));
1615df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
1625df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	fcoe_hdr = (struct fcoe_hdr *)skb->data;
1635df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	if (FC_FCOE_DECAPS_VER(fcoe_hdr) != FC_FCOE_VER)
16478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		goto drop;
1655df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
1665df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	fp = (struct fc_frame *)skb;
1675df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	fc_frame_init(fp);
1685df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	fr_sof(fp) = fcoe_hdr->fcoe_sof;
1695df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	skb_pull(skb, sizeof(struct fcoe_hdr));
17078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	skb_reset_transport_header(skb);
1715df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
17278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	ft = (struct fcoe_crc_eof *)(skb->data + skb->len - sizeof(*ft));
1735df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	fr_eof(fp) = ft->fcoe_eof;
17478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	skb_trim(skb, skb->len - sizeof(*ft));
1755df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	return 0;
17678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholtdrop:
17778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	dev_kfree_skb_irq(skb);
17878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	return -1;
1795df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar}
1805df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
18178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt/**
18278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * fnic_update_mac_locked() - set data MAC address and filters.
18378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * @fnic:	fnic instance.
18478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * @new:	newly-assigned FCoE MAC address.
18578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt *
18678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * Called with the fnic lock held.
18778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt */
18878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholtvoid fnic_update_mac_locked(struct fnic *fnic, u8 *new)
1895df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar{
19078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	u8 *ctl = fnic->ctlr.ctl_src_addr;
19178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	u8 *data = fnic->data_src_addr;
1925df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
19378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	if (is_zero_ether_addr(new))
19478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		new = ctl;
19578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	if (!compare_ether_addr(data, new))
19678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		return;
19778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, "update_mac %pM\n", new);
19878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	if (!is_zero_ether_addr(data) && compare_ether_addr(data, ctl))
19978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		vnic_dev_del_addr(fnic->vdev, data);
20078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	memcpy(data, new, ETH_ALEN);
20178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	if (compare_ether_addr(new, ctl))
20278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		vnic_dev_add_addr(fnic->vdev, new);
20378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt}
2045df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
20578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt/**
20678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * fnic_update_mac() - set data MAC address and filters.
20778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * @lport:	local port.
20878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * @new:	newly-assigned FCoE MAC address.
20978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt */
21078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholtvoid fnic_update_mac(struct fc_lport *lport, u8 *new)
21178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt{
21278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	struct fnic *fnic = lport_priv(lport);
2135df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
21478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	spin_lock_irq(&fnic->fnic_lock);
21578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	fnic_update_mac_locked(fnic, new);
21678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	spin_unlock_irq(&fnic->fnic_lock);
21778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt}
2185df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
21978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt/**
22078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * fnic_set_port_id() - set the port_ID after successful FLOGI.
22178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * @lport:	local port.
22278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * @port_id:	assigned FC_ID.
22378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * @fp:		received frame containing the FLOGI accept or NULL.
22478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt *
22578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * This is called from libfc when a new FC_ID has been assigned.
22678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * This causes us to reset the firmware to FC_MODE and setup the new MAC
22778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * address and FC_ID.
22878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt *
22978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * It is also called with FC_ID 0 when we're logged off.
23078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt *
23178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * If the FC_ID is due to point-to-point, fp may be NULL.
23278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt */
23378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholtvoid fnic_set_port_id(struct fc_lport *lport, u32 port_id, struct fc_frame *fp)
23478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt{
23578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	struct fnic *fnic = lport_priv(lport);
23678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	u8 *mac;
23778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	int ret;
2385df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
23978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	FNIC_FCS_DBG(KERN_DEBUG, lport->host, "set port_id %x fp %p\n",
24078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		     port_id, fp);
2415df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
24278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	/*
24378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	 * If we're clearing the FC_ID, change to use the ctl_src_addr.
24478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	 * Set ethernet mode to send FLOGI.
24578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	 */
24678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	if (!port_id) {
24778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		fnic_update_mac(lport, fnic->ctlr.ctl_src_addr);
24878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		fnic_set_eth_mode(fnic);
24978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		return;
25078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	}
2515df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
25278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	if (fp) {
25378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		mac = fr_cb(fp)->granted_mac;
25478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		if (is_zero_ether_addr(mac)) {
25578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt			/* non-FIP - FLOGI already accepted - ignore return */
25678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt			fcoe_ctlr_recv_flogi(&fnic->ctlr, lport, fp);
2575df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		}
25878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		fnic_update_mac(lport, mac);
25978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	}
2605df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
26178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	/* Change state to reflect transition to FC mode */
26278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	spin_lock_irq(&fnic->fnic_lock);
26378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	if (fnic->state == FNIC_IN_ETH_MODE || fnic->state == FNIC_IN_FC_MODE)
2645df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		fnic->state = FNIC_IN_ETH_TRANS_FC_MODE;
26578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	else {
2665df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host,
2675df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			     "Unexpected fnic state %s while"
2685df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			     " processing flogi resp\n",
2695df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			     fnic_state_to_str(fnic->state));
27078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		spin_unlock_irq(&fnic->fnic_lock);
27178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		return;
2725df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	}
27378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	spin_unlock_irq(&fnic->fnic_lock);
2745df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
2755df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	/*
27678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	 * Send FLOGI registration to firmware to set up FC mode.
27778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	 * The new address will be set up when registration completes.
2785df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	 */
27978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	ret = fnic_flogi_reg_handler(fnic, port_id);
2805df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
2815df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	if (ret < 0) {
28278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		spin_lock_irq(&fnic->fnic_lock);
2835df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		if (fnic->state == FNIC_IN_ETH_TRANS_FC_MODE)
2845df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			fnic->state = FNIC_IN_ETH_MODE;
28578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		spin_unlock_irq(&fnic->fnic_lock);
2865df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	}
2875df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar}
2885df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
2895df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekarstatic void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc
2905df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				    *cq_desc, struct vnic_rq_buf *buf,
2915df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				    int skipped __attribute__((unused)),
2925df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				    void *opaque)
2935df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar{
2945df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fnic *fnic = vnic_dev_priv(rq->vdev);
2955df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct sk_buff *skb;
2965df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fc_frame *fp;
2975df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	unsigned int eth_hdrs_stripped;
2985df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	u8 type, color, eop, sop, ingress_port, vlan_stripped;
2995df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	u8 fcoe = 0, fcoe_sof, fcoe_eof;
3005df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	u8 fcoe_fc_crc_ok = 1, fcoe_enc_error = 0;
3015df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	u8 tcp_udp_csum_ok, udp, tcp, ipv4_csum_ok;
3025df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	u8 ipv6, ipv4, ipv4_fragment, rss_type, csum_not_calc;
3035df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	u8 fcs_ok = 1, packet_error = 0;
3045df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	u16 q_number, completed_index, bytes_written = 0, vlan, checksum;
3055df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	u32 rss_hash;
3065df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	u16 exchange_id, tmpl;
3075df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	u8 sof = 0;
3085df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	u8 eof = 0;
3095df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	u32 fcp_bytes_written = 0;
3105df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	unsigned long flags;
3115df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
3125df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	pci_unmap_single(fnic->pdev, buf->dma_addr, buf->len,
3135df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			 PCI_DMA_FROMDEVICE);
3145df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	skb = buf->os_buf;
31578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	fp = (struct fc_frame *)skb;
3165df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	buf->os_buf = NULL;
3175df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
3185df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	cq_desc_dec(cq_desc, &type, &color, &q_number, &completed_index);
3195df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	if (type == CQ_DESC_TYPE_RQ_FCP) {
3205df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		cq_fcp_rq_desc_dec((struct cq_fcp_rq_desc *)cq_desc,
3215df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				   &type, &color, &q_number, &completed_index,
3225df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				   &eop, &sop, &fcoe_fc_crc_ok, &exchange_id,
3235df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				   &tmpl, &fcp_bytes_written, &sof, &eof,
3245df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				   &ingress_port, &packet_error,
3255df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				   &fcoe_enc_error, &fcs_ok, &vlan_stripped,
3265df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				   &vlan);
3275df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		eth_hdrs_stripped = 1;
32878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		skb_trim(skb, fcp_bytes_written);
32978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		fr_sof(fp) = sof;
33078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		fr_eof(fp) = eof;
3315df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
3325df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	} else if (type == CQ_DESC_TYPE_RQ_ENET) {
3335df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		cq_enet_rq_desc_dec((struct cq_enet_rq_desc *)cq_desc,
3345df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				    &type, &color, &q_number, &completed_index,
3355df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				    &ingress_port, &fcoe, &eop, &sop,
3365df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				    &rss_type, &csum_not_calc, &rss_hash,
3375df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				    &bytes_written, &packet_error,
3385df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				    &vlan_stripped, &vlan, &checksum,
3395df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				    &fcoe_sof, &fcoe_fc_crc_ok,
3405df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				    &fcoe_enc_error, &fcoe_eof,
3415df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				    &tcp_udp_csum_ok, &udp, &tcp,
3425df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				    &ipv4_csum_ok, &ipv6, &ipv4,
3435df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				    &ipv4_fragment, &fcs_ok);
3445df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		eth_hdrs_stripped = 0;
34578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		skb_trim(skb, bytes_written);
34678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		if (!fcs_ok) {
34778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt			FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host,
34878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt				     "fcs error.  dropping packet.\n");
34978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt			goto drop;
35078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		}
35178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		if (fnic_import_rq_eth_pkt(fnic, skb))
35278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt			return;
3535df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
3545df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	} else {
3555df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		/* wrong CQ type*/
3565df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		shost_printk(KERN_ERR, fnic->lport->host,
3575df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			     "fnic rq_cmpl wrong cq type x%x\n", type);
3585df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		goto drop;
3595df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	}
3605df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
3615df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	if (!fcs_ok || packet_error || !fcoe_fc_crc_ok || fcoe_enc_error) {
3625df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host,
3635df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			     "fnic rq_cmpl fcoe x%x fcsok x%x"
3645df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			     " pkterr x%x fcoe_fc_crc_ok x%x, fcoe_enc_err"
3655df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			     " x%x\n",
3665df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			     fcoe, fcs_ok, packet_error,
3675df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			     fcoe_fc_crc_ok, fcoe_enc_error);
3685df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		goto drop;
3695df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	}
3705df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
3715df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	spin_lock_irqsave(&fnic->fnic_lock, flags);
3725df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	if (fnic->stop_rx_link_events) {
3735df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
3745df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		goto drop;
3755df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	}
3765df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	fr_dev(fp) = fnic->lport;
3775df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
3785df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
3795df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	skb_queue_tail(&fnic->frame_queue, skb);
3805df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	queue_work(fnic_event_queue, &fnic->frame_work);
3815df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
3825df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	return;
3835df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekardrop:
3845df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	dev_kfree_skb_irq(skb);
3855df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar}
3865df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
3875df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekarstatic int fnic_rq_cmpl_handler_cont(struct vnic_dev *vdev,
3885df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				     struct cq_desc *cq_desc, u8 type,
3895df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				     u16 q_number, u16 completed_index,
3905df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				     void *opaque)
3915df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar{
3925df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fnic *fnic = vnic_dev_priv(vdev);
3935df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
3945df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	vnic_rq_service(&fnic->rq[q_number], cq_desc, completed_index,
3955df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			VNIC_RQ_RETURN_DESC, fnic_rq_cmpl_frame_recv,
3965df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			NULL);
3975df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	return 0;
3985df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar}
3995df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
4005df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekarint fnic_rq_cmpl_handler(struct fnic *fnic, int rq_work_to_do)
4015df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar{
4025df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	unsigned int tot_rq_work_done = 0, cur_work_done;
4035df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	unsigned int i;
4045df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	int err;
4055df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
4065df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	for (i = 0; i < fnic->rq_count; i++) {
4075df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		cur_work_done = vnic_cq_service(&fnic->cq[i], rq_work_to_do,
4085df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar						fnic_rq_cmpl_handler_cont,
4095df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar						NULL);
4105df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		if (cur_work_done) {
4115df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			err = vnic_rq_fill(&fnic->rq[i], fnic_alloc_rq_frame);
4125df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			if (err)
4135df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				shost_printk(KERN_ERR, fnic->lport->host,
41425985edcedea6396277003854657b5f3cb31a628Lucas De Marchi					     "fnic_alloc_rq_frame can't alloc"
4155df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar					     " frame\n");
4165df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		}
4175df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		tot_rq_work_done += cur_work_done;
4185df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	}
4195df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
4205df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	return tot_rq_work_done;
4215df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar}
4225df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
4235df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar/*
4245df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar * This function is called once at init time to allocate and fill RQ
4255df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar * buffers. Subsequently, it is called in the interrupt context after RQ
4265df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar * buffer processing to replenish the buffers in the RQ
4275df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar */
4285df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekarint fnic_alloc_rq_frame(struct vnic_rq *rq)
4295df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar{
4305df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fnic *fnic = vnic_dev_priv(rq->vdev);
4315df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct sk_buff *skb;
4325df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	u16 len;
4335df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	dma_addr_t pa;
4345df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
4355df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	len = FC_FRAME_HEADROOM + FC_MAX_FRAME + FC_FRAME_TAILROOM;
4365df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	skb = dev_alloc_skb(len);
4375df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	if (!skb) {
4385df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host,
4395df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			     "Unable to allocate RQ sk_buff\n");
4405df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		return -ENOMEM;
4415df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	}
4425df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	skb_reset_mac_header(skb);
4435df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	skb_reset_transport_header(skb);
4445df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	skb_reset_network_header(skb);
4455df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	skb_put(skb, len);
4465df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	pa = pci_map_single(fnic->pdev, skb->data, len, PCI_DMA_FROMDEVICE);
4475df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	fnic_queue_rq_desc(rq, skb, pa, len);
4485df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	return 0;
4495df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar}
4505df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
4515df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekarvoid fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf)
4525df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar{
4535df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fc_frame *fp = buf->os_buf;
4545df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fnic *fnic = vnic_dev_priv(rq->vdev);
4555df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
4565df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	pci_unmap_single(fnic->pdev, buf->dma_addr, buf->len,
4575df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			 PCI_DMA_FROMDEVICE);
4585df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
4595df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	dev_kfree_skb(fp_skb(fp));
4605df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	buf->os_buf = NULL;
4615df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar}
4625df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
46378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt/**
46478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * fnic_eth_send() - Send Ethernet frame.
46578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * @fip:	fcoe_ctlr instance.
46678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * @skb:	Ethernet Frame, FIP, without VLAN encapsulation.
46778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt */
46878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholtvoid fnic_eth_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
4695df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar{
47078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	struct fnic *fnic = fnic_from_ctlr(fip);
47178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	struct vnic_wq *wq = &fnic->wq[0];
47278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	dma_addr_t pa;
47378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	struct ethhdr *eth_hdr;
47478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	struct vlan_ethhdr *vlan_hdr;
47578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	unsigned long flags;
47678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt
47778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	if (!fnic->vlan_hw_insert) {
47878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		eth_hdr = (struct ethhdr *)skb_mac_header(skb);
47978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		vlan_hdr = (struct vlan_ethhdr *)skb_push(skb,
48078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt				sizeof(*vlan_hdr) - sizeof(*eth_hdr));
48178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		memcpy(vlan_hdr, eth_hdr, 2 * ETH_ALEN);
48278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		vlan_hdr->h_vlan_proto = htons(ETH_P_8021Q);
48378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		vlan_hdr->h_vlan_encapsulated_proto = eth_hdr->h_proto;
48478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		vlan_hdr->h_vlan_TCI = htons(fnic->vlan_id);
48578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	}
48678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt
48778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	pa = pci_map_single(fnic->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
48878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt
48978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	spin_lock_irqsave(&fnic->wq_lock[0], flags);
49078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	if (!vnic_wq_desc_avail(wq)) {
49178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		pci_unmap_single(fnic->pdev, pa, skb->len, PCI_DMA_TODEVICE);
49278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		spin_unlock_irqrestore(&fnic->wq_lock[0], flags);
49378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		kfree_skb(skb);
49478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		return;
49578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	}
49678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt
49778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	fnic_queue_wq_eth_desc(wq, skb, pa, skb->len,
49878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt			       fnic->vlan_hw_insert, fnic->vlan_id, 1);
49978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	spin_unlock_irqrestore(&fnic->wq_lock[0], flags);
5005df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar}
5015df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
50278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt/*
50378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * Send FC frame.
50478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt */
50578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholtstatic int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp)
5065df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar{
5075df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct vnic_wq *wq = &fnic->wq[0];
5085df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct sk_buff *skb;
5095df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	dma_addr_t pa;
5105df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct ethhdr *eth_hdr;
5115df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct vlan_ethhdr *vlan_hdr;
5125df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fcoe_hdr *fcoe_hdr;
5135df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fc_frame_header *fh;
5145df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	u32 tot_len, eth_hdr_len;
5155df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	int ret = 0;
5165df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	unsigned long flags;
5175df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
5185df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	fh = fc_frame_header_get(fp);
5195df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	skb = fp_skb(fp);
5205df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
52178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ) &&
52278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	    fcoe_ctlr_els_send(&fnic->ctlr, fnic->lport, skb))
52378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		return 0;
52478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt
5255df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	if (!fnic->vlan_hw_insert) {
5265df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		eth_hdr_len = sizeof(*vlan_hdr) + sizeof(*fcoe_hdr);
5275df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		vlan_hdr = (struct vlan_ethhdr *)skb_push(skb, eth_hdr_len);
5285df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		eth_hdr = (struct ethhdr *)vlan_hdr;
5295df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		vlan_hdr->h_vlan_proto = htons(ETH_P_8021Q);
5305df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		vlan_hdr->h_vlan_encapsulated_proto = htons(ETH_P_FCOE);
5315df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		vlan_hdr->h_vlan_TCI = htons(fnic->vlan_id);
5325df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		fcoe_hdr = (struct fcoe_hdr *)(vlan_hdr + 1);
5335df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	} else {
5345df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		eth_hdr_len = sizeof(*eth_hdr) + sizeof(*fcoe_hdr);
5355df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		eth_hdr = (struct ethhdr *)skb_push(skb, eth_hdr_len);
5365df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		eth_hdr->h_proto = htons(ETH_P_FCOE);
5375df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		fcoe_hdr = (struct fcoe_hdr *)(eth_hdr + 1);
5385df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	}
5395df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
54078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	if (fnic->ctlr.map_dest)
5415df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		fc_fcoe_set_mac(eth_hdr->h_dest, fh->fh_d_id);
54278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	else
54378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		memcpy(eth_hdr->h_dest, fnic->ctlr.dest_addr, ETH_ALEN);
54478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	memcpy(eth_hdr->h_source, fnic->data_src_addr, ETH_ALEN);
5455df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
5465df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	tot_len = skb->len;
5475df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	BUG_ON(tot_len % 4);
5485df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
5495df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	memset(fcoe_hdr, 0, sizeof(*fcoe_hdr));
5505df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	fcoe_hdr->fcoe_sof = fr_sof(fp);
5515df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	if (FC_FCOE_VER)
5525df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		FC_FCOE_ENCAPS_VER(fcoe_hdr, FC_FCOE_VER);
5535df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
5545df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	pa = pci_map_single(fnic->pdev, eth_hdr, tot_len, PCI_DMA_TODEVICE);
5555df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
5565df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	spin_lock_irqsave(&fnic->wq_lock[0], flags);
5575df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
5585df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	if (!vnic_wq_desc_avail(wq)) {
5595df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		pci_unmap_single(fnic->pdev, pa,
5605df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				 tot_len, PCI_DMA_TODEVICE);
5615df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		ret = -1;
5625df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		goto fnic_send_frame_end;
5635df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	}
5645df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
5655df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	fnic_queue_wq_desc(wq, skb, pa, tot_len, fr_eof(fp),
5665df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			   fnic->vlan_hw_insert, fnic->vlan_id, 1, 1, 1);
5675df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekarfnic_send_frame_end:
5685df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	spin_unlock_irqrestore(&fnic->wq_lock[0], flags);
5695df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
5705df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	if (ret)
5715df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		dev_kfree_skb_any(fp_skb(fp));
5725df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
5735df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	return ret;
5745df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar}
5755df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
5765df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar/*
5775df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar * fnic_send
5785df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar * Routine to send a raw frame
5795df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar */
5805df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekarint fnic_send(struct fc_lport *lp, struct fc_frame *fp)
5815df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar{
5825df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fnic *fnic = lport_priv(lp);
5835df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	unsigned long flags;
5845df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
5855df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	if (fnic->in_remove) {
5865df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		dev_kfree_skb(fp_skb(fp));
58778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		return -1;
5885df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	}
5895df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
59078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	/*
59178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	 * Queue frame if in a transitional state.
59278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	 * This occurs while registering the Port_ID / MAC address after FLOGI.
59378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	 */
59478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	spin_lock_irqsave(&fnic->fnic_lock, flags);
59578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	if (fnic->state != FNIC_IN_FC_MODE && fnic->state != FNIC_IN_ETH_MODE) {
59678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		skb_queue_tail(&fnic->tx_queue, fp_skb(fp));
59778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
59878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		return 0;
59978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	}
60078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
6015df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
60278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	return fnic_send_frame(fnic, fp);
60378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt}
6045df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
60578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt/**
60678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * fnic_flush_tx() - send queued frames.
60778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * @fnic: fnic device
60878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt *
60978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * Send frames that were waiting to go out in FC or Ethernet mode.
61078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * Whenever changing modes we purge queued frames, so these frames should
61178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * be queued for the stable mode that we're in, either FC or Ethernet.
61278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt *
61378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * Called without fnic_lock held.
61478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt */
61578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholtvoid fnic_flush_tx(struct fnic *fnic)
61678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt{
61778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	struct sk_buff *skb;
61878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	struct fc_frame *fp;
6195df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
620d9e9ab56b687da0b3ecb29f7a77f25aa7ae078fbBrian Uchino	while ((skb = skb_dequeue(&fnic->tx_queue))) {
62178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		fp = (struct fc_frame *)skb;
62278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		fnic_send_frame(fnic, fp);
62378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	}
62478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt}
6255df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
62678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt/**
62778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * fnic_set_eth_mode() - put fnic into ethernet mode.
62878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * @fnic: fnic device
62978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt *
63078112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt * Called without fnic lock held.
63178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt */
63278112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholtstatic void fnic_set_eth_mode(struct fnic *fnic)
63378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt{
63478112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	unsigned long flags;
63578112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	enum fnic_state old_state;
63678112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	int ret;
63778112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt
63878112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	spin_lock_irqsave(&fnic->fnic_lock, flags);
63978112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholtagain:
6405df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	old_state = fnic->state;
6415df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	switch (old_state) {
6425df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	case FNIC_IN_FC_MODE:
6435df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	case FNIC_IN_ETH_TRANS_FC_MODE:
6445df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	default:
6455df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		fnic->state = FNIC_IN_FC_TRANS_ETH_MODE;
6465df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
6475df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
6485df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		ret = fnic_fw_reset_handler(fnic);
6495df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
6505df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		spin_lock_irqsave(&fnic->fnic_lock, flags);
6515df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		if (fnic->state != FNIC_IN_FC_TRANS_ETH_MODE)
6525df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			goto again;
65378112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt		if (ret)
6545df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			fnic->state = old_state;
6555df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		break;
6565df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
6575df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	case FNIC_IN_FC_TRANS_ETH_MODE:
6585df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	case FNIC_IN_ETH_MODE:
6595df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		break;
6605df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	}
66178112e5558064cb4d2e355aed87b2036fcdfe3ddJoe Eykholt	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
6625df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar}
6635df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
6645df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekarstatic void fnic_wq_complete_frame_send(struct vnic_wq *wq,
6655df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar					struct cq_desc *cq_desc,
6665df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar					struct vnic_wq_buf *buf, void *opaque)
6675df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar{
6685df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct sk_buff *skb = buf->os_buf;
6695df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fc_frame *fp = (struct fc_frame *)skb;
6705df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fnic *fnic = vnic_dev_priv(wq->vdev);
6715df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
6725df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	pci_unmap_single(fnic->pdev, buf->dma_addr,
6735df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			 buf->len, PCI_DMA_TODEVICE);
6745df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	dev_kfree_skb_irq(fp_skb(fp));
6755df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	buf->os_buf = NULL;
6765df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar}
6775df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
6785df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekarstatic int fnic_wq_cmpl_handler_cont(struct vnic_dev *vdev,
6795df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				     struct cq_desc *cq_desc, u8 type,
6805df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				     u16 q_number, u16 completed_index,
6815df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar				     void *opaque)
6825df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar{
6835df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fnic *fnic = vnic_dev_priv(vdev);
6845df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	unsigned long flags;
6855df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
6865df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	spin_lock_irqsave(&fnic->wq_lock[q_number], flags);
6875df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	vnic_wq_service(&fnic->wq[q_number], cq_desc, completed_index,
6885df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			fnic_wq_complete_frame_send, NULL);
6895df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	spin_unlock_irqrestore(&fnic->wq_lock[q_number], flags);
6905df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
6915df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	return 0;
6925df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar}
6935df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
6945df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekarint fnic_wq_cmpl_handler(struct fnic *fnic, int work_to_do)
6955df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar{
6965df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	unsigned int wq_work_done = 0;
6975df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	unsigned int i;
6985df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
6995df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	for (i = 0; i < fnic->raw_wq_count; i++) {
7005df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar		wq_work_done  += vnic_cq_service(&fnic->cq[fnic->rq_count+i],
7015df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar						 work_to_do,
7025df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar						 fnic_wq_cmpl_handler_cont,
7035df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar						 NULL);
7045df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	}
7055df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
7065df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	return wq_work_done;
7075df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar}
7085df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
7095df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
7105df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekarvoid fnic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf)
7115df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar{
7125df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fc_frame *fp = buf->os_buf;
7135df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	struct fnic *fnic = vnic_dev_priv(wq->vdev);
7145df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
7155df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	pci_unmap_single(fnic->pdev, buf->dma_addr,
7165df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar			 buf->len, PCI_DMA_TODEVICE);
7175df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar
7185df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	dev_kfree_skb(fp_skb(fp));
7195df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar	buf->os_buf = NULL;
7205df6d737dd4b0fe9eccf943abb3677cfea05a6c4Abhijeet Joglekar}
721