Commit a63e78eb authored by Karan Tilak Kumar's avatar Karan Tilak Kumar Committed by Martin K. Petersen
Browse files

scsi: fnic: Add support for fabric based solicited requests and responses



Add fdls_disc.c to support fabric based solicited requests and responses.

Clean up obsolete code but keep the function template so as to not break
compilation.

Remove duplicate definitions from header files.

Modify definitions of data members.

Reported-by: default avatarkernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202406112309.8GiDUvIM-lkp@intel.com/
Closes: https://lore.kernel.org/oe-kbuild-all/202406120201.VakI9Dly-lkp@intel.com/
Closes: https://lore.kernel.org/oe-kbuild-all/202412080837.2JU0r2Ny-lkp@intel.com/


Reviewed-by: default avatarSesidhar Baddela <sebaddel@cisco.com>
Co-developed-by: default avatarGian Carlo Boffa <gcboffa@cisco.com>
Signed-off-by: default avatarGian Carlo Boffa <gcboffa@cisco.com>
Co-developed-by: default avatarArulprabhu Ponnusamy <arulponn@cisco.com>
Signed-off-by: default avatarArulprabhu Ponnusamy <arulponn@cisco.com>
Co-developed-by: default avatarArun Easi <aeasi@cisco.com>
Signed-off-by: default avatarArun Easi <aeasi@cisco.com>
Co-developed-by: default avatarKaran Tilak Kumar <kartilak@cisco.com>
Signed-off-by: default avatarKaran Tilak Kumar <kartilak@cisco.com>
Link: https://lore.kernel.org/r/20241212020312.4786-4-kartilak@cisco.com


Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent d859d05c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ fnic-y := \
	fnic_main.o \
	fnic_res.o \
	fnic_fcs.o \
	fdls_disc.o \
	fnic_scsi.o \
	fnic_trace.o \
	fnic_debugfs.o \
+2180 −0

File added.

Preview size limit exceeded, changes collapsed.

+102 −2
Original line number Diff line number Diff line
@@ -12,6 +12,10 @@
#include <linux/bitops.h>
#include <scsi/libfc.h>
#include <scsi/libfcoe.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_fc.h>
#include <scsi/fc_frame.h>
#include "fnic_io.h"
#include "fnic_res.h"
#include "fnic_trace.h"
@@ -24,6 +28,7 @@
#include "vnic_intr.h"
#include "vnic_stats.h"
#include "vnic_scsi.h"
#include "fnic_fdls.h"

#define DRV_NAME		"fnic"
#define DRV_DESCRIPTION		"Cisco FCoE HBA Driver"
@@ -31,6 +36,7 @@
#define PFX			DRV_NAME ": "
#define DFX                     DRV_NAME "%d: "

#define FABRIC_LOGO_MAX_RETRY 3
#define DESC_CLEAN_LOW_WATERMARK 8
#define FNIC_UCSM_DFLT_THROTTLE_CNT_BLD	16 /* UCSM default throttle count */
#define FNIC_MIN_IO_REQ			256 /* Min IO throttle count */
@@ -38,6 +44,7 @@
#define FNIC_DFLT_IO_REQ        256 /* Default scsi_cmnd tag map entries */
#define FNIC_DFLT_QUEUE_DEPTH	256
#define	FNIC_STATS_RATE_LIMIT	4 /* limit rate at which stats are pulled up */
#define LUN0_DELAY_TIME			9

/*
 * Tag bits used for special requests.
@@ -75,6 +82,8 @@
#define FNIC_DEV_RST_TERM_DONE          BIT(20)
#define FNIC_DEV_RST_ABTS_PENDING       BIT(21)

#define IS_FNIC_FCP_INITIATOR(fnic) (fnic->role == FNIC_ROLE_FCP_INITIATOR)

/*
 * fnic private data per SCSI command.
 * These fields are locked by the hashed io_req_lock.
@@ -213,12 +222,26 @@ enum fnic_state {

struct mempool;

enum fnic_role_e {
	FNIC_ROLE_FCP_INITIATOR = 0,
};

enum fnic_evt {
	FNIC_EVT_START_VLAN_DISC = 1,
	FNIC_EVT_START_FCF_DISC = 2,
	FNIC_EVT_MAX,
};

struct fnic_frame_list {
	/*
	 * Link to frame lists
	 */
	struct list_head links;
	void *fp;
	int frame_len;
	int rx_ethhdr_stripped;
};

struct fnic_event {
	struct list_head list;
	struct fnic *fnic;
@@ -235,6 +258,8 @@ struct fnic_cpy_wq {
/* Per-instance private data structure */
struct fnic {
	int fnic_num;
	enum fnic_role_e role;
	struct fnic_iport_s iport;
	struct fc_lport *lport;
	struct fcoe_ctlr ctlr;		/* FIP FCoE controller structure */
	struct vnic_dev_bar bar0;
@@ -278,6 +303,7 @@ struct fnic {
	unsigned long state_flags;	/* protected by host lock */
	enum fnic_state state;
	spinlock_t fnic_lock;
	unsigned long lock_flags;

	u16 vlan_id;	                /* VLAN tag including priority */
	u8 data_src_addr[ETH_ALEN];
@@ -307,7 +333,9 @@ struct fnic {
	struct work_struct frame_work;
	struct work_struct flush_work;
	struct sk_buff_head frame_queue;
	struct sk_buff_head tx_queue;
	struct list_head tx_queue;
	mempool_t *frame_pool;
	mempool_t *frame_elem_pool;

	/*** FIP related data members  -- start ***/
	void (*set_vlan)(struct fnic *, u16 vlan);
@@ -361,6 +389,9 @@ void fnic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf);
void fnic_handle_frame(struct work_struct *work);
void fnic_handle_link(struct work_struct *work);
void fnic_handle_event(struct work_struct *work);
void fdls_reclaim_oxid_handler(struct work_struct *work);
void fdls_schedule_oxid_free(struct fnic_iport_s *iport, uint16_t *active_oxid);
void fdls_schedule_oxid_free_retry_work(struct work_struct *work);
int fnic_rq_cmpl_handler(struct fnic *fnic, int);
int fnic_alloc_rq_frame(struct vnic_rq *rq);
void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf);
@@ -397,7 +428,6 @@ void fnic_handle_fip_frame(struct work_struct *work);
void fnic_handle_fip_event(struct fnic *fnic);
void fnic_fcoe_reset_vlans(struct fnic *fnic);
void fnic_fcoe_evlist_free(struct fnic *fnic);
extern void fnic_handle_fip_timer(struct fnic *fnic);

static inline int
fnic_chk_state_flags_locked(struct fnic *fnic, unsigned long st_flags)
@@ -406,4 +436,74 @@ fnic_chk_state_flags_locked(struct fnic *fnic, unsigned long st_flags)
}
void __fnic_set_state_flags(struct fnic *, unsigned long, unsigned long);
void fnic_dump_fchost_stats(struct Scsi_Host *, struct fc_host_statistics *);
void fnic_free_txq(struct list_head *head);

struct fnic_scsi_iter_data {
	struct fnic *fnic;
	void *data1;
	void *data2;
	bool (*fn)(struct fnic *fnic, struct scsi_cmnd *sc,
			void *data1, void *data2);
};

static inline bool
fnic_io_iter_handler(struct scsi_cmnd *sc, void *iter_data)
{
	struct fnic_scsi_iter_data *iter = iter_data;

	return iter->fn(iter->fnic, sc, iter->data1, iter->data2);
}

static inline void
fnic_scsi_io_iter(struct fnic *fnic,
		bool (*fn)(struct fnic *fnic, struct scsi_cmnd *sc,
				void *data1, void *data2),
		void *data1, void *data2)
{
	struct fnic_scsi_iter_data iter_data = {
		.fn = fn,
		.fnic = fnic,
		.data1 = data1,
		.data2 = data2,
	};
	scsi_host_busy_iter(fnic->lport->host, fnic_io_iter_handler, &iter_data);
}

#ifdef FNIC_DEBUG
static inline void
fnic_debug_dump(struct fnic *fnic, uint8_t *u8arr, int len)
{
	int i;

	for (i = 0; i < len; i = i+8) {
		FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num,
		    "%d: %02x %02x %02x %02x %02x %02x %02x %02x", i / 8,
		    u8arr[i + 0], u8arr[i + 1], u8arr[i + 2], u8arr[i + 3],
		    u8arr[i + 4], u8arr[i + 5], u8arr[i + 6], u8arr[i + 7]);
	}
}

static inline void
fnic_debug_dump_fc_frame(struct fnic *fnic, struct fc_frame_header *fchdr,
				int len, char *pfx)
{
	uint32_t s_id, d_id;

	s_id = ntoh24(fchdr->fh_s_id);
	d_id = ntoh24(fchdr->fh_d_id);
	FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num,
		"%s packet contents: sid/did/type/oxid = 0x%x/0x%x/0x%x/0x%x (len = %d)\n",
		pfx, s_id, d_id, fchdr->fh_type,
		FNIC_STD_GET_OX_ID(fchdr), len);

	fnic_debug_dump(fnic, (uint8_t *)fchdr, len);

}
#else /* FNIC_DEBUG */
static inline void
fnic_debug_dump(struct fnic *fnic, uint8_t *u8arr, int len) {}
static inline void
fnic_debug_dump_fc_frame(struct fnic *fnic, struct fc_frame_header *fchdr,
				uint32_t len, char *pfx) {}
#endif /* FNIC_DEBUG */
#endif /* _FNIC_H_ */
+251 −170
Original line number Diff line number Diff line
@@ -17,9 +17,12 @@
#include <scsi/fc/fc_fcoe.h>
#include <scsi/fc_frame.h>
#include <scsi/libfc.h>
#include <scsi/scsi_transport_fc.h>
#include "fnic_io.h"
#include "fnic.h"
#include "fnic_fip.h"
#include "fnic_fdls.h"
#include "fdls_fc.h"
#include "cq_enet_desc.h"
#include "cq_exch_desc.h"

@@ -28,12 +31,91 @@ struct workqueue_struct *fnic_fip_queue;
struct workqueue_struct *fnic_event_queue;

static void fnic_set_eth_mode(struct fnic *);
static void fnic_fcoe_send_vlan_req(struct fnic *fnic);
static void fnic_fcoe_start_fcf_disc(struct fnic *fnic);
static void fnic_fcoe_process_vlan_resp(struct fnic *fnic, struct sk_buff *);
static int fnic_fcoe_vlan_check(struct fnic *fnic, u16 flag);
static int fnic_fcoe_handle_fip_frame(struct fnic *fnic, struct sk_buff *skb);

static uint8_t FCOE_ALL_FCF_MAC[6] = FC_FCOE_FLOGI_MAC;

/*
 * Internal Functions
 * This function will initialize the src_mac address to be
 * used in outgoing frames
 */
static inline void fnic_fdls_set_fcoe_srcmac(struct fnic *fnic,
							 uint8_t *src_mac)
{
	FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num,
				 "Setting src mac: %02x:%02x:%02x:%02x:%02x:%02x",
				 src_mac[0], src_mac[1], src_mac[2], src_mac[3],
				 src_mac[4], src_mac[5]);

	memcpy(fnic->iport.fpma, src_mac, 6);
}

/*
 * This function will initialize the dst_mac address to be
 * used in outgoing frames
 */
static inline  void fnic_fdls_set_fcoe_dstmac(struct fnic *fnic,
							 uint8_t *dst_mac)
{
	FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num,
				 "Setting dst mac: %02x:%02x:%02x:%02x:%02x:%02x",
				 dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3],
				 dst_mac[4], dst_mac[5]);

	memcpy(fnic->iport.fcfmac, dst_mac, 6);
}

/*
 * FPMA can be either taken from ethhdr(dst_mac) or flogi resp
 * or derive from FC_MAP and FCID combination. While it should be
 * same, revisit this if there is any possibility of not-correct.
 */
void fnic_fdls_learn_fcoe_macs(struct fnic_iport_s *iport, void *rx_frame,
							   uint8_t *fcid)
{
	struct fnic *fnic = iport->fnic;
	struct ethhdr *ethhdr = (struct ethhdr *) rx_frame;
	uint8_t fcmac[6] = { 0x0E, 0xFC, 0x00, 0x00, 0x00, 0x00 };

	memcpy(&fcmac[3], fcid, 3);

	FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num,
				 "learn fcoe: dst_mac: %02x:%02x:%02x:%02x:%02x:%02x",
				 ethhdr->h_dest[0], ethhdr->h_dest[1],
				 ethhdr->h_dest[2], ethhdr->h_dest[3],
				 ethhdr->h_dest[4], ethhdr->h_dest[5]);

	FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num,
				 "learn fcoe: fc_mac: %02x:%02x:%02x:%02x:%02x:%02x",
				 fcmac[0], fcmac[1], fcmac[2], fcmac[3], fcmac[4],
				 fcmac[5]);

	fnic_fdls_set_fcoe_srcmac(fnic, fcmac);
	fnic_fdls_set_fcoe_dstmac(fnic, ethhdr->h_source);
}

void fnic_fdls_init(struct fnic *fnic, int usefip)
{
	struct fnic_iport_s *iport = &fnic->iport;

	/* Initialize iPort structure */
	iport->state = FNIC_IPORT_STATE_INIT;
	iport->fnic = fnic;
	iport->usefip = usefip;

	FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num,
				 "iportsrcmac: %02x:%02x:%02x:%02x:%02x:%02x",
				 iport->hwmac[0], iport->hwmac[1], iport->hwmac[2],
				 iport->hwmac[3], iport->hwmac[4], iport->hwmac[5]);

	INIT_LIST_HEAD(&iport->tport_list);
	INIT_LIST_HEAD(&iport->tport_list_pending_del);
}

void fnic_handle_link(struct work_struct *work)
{
	struct fnic *fnic = container_of(work, struct fnic, link_work);
@@ -363,7 +445,7 @@ static inline int is_fnic_fip_flogi_reject(struct fcoe_ctlr *fip,
	return 0;
}

static void fnic_fcoe_send_vlan_req(struct fnic *fnic)
void fnic_fcoe_send_vlan_req(struct fnic *fnic)
{
	struct fcoe_ctlr *fip = &fnic->ctlr;
	struct fnic_stats *fnic_stats = &fnic->fnic_stats;
@@ -1068,116 +1150,137 @@ void fnic_eth_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
/*
 * Send FC frame.
 */
static int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp)
static int fnic_send_frame(struct fnic *fnic, void *frame, int frame_len)
{
	struct vnic_wq *wq = &fnic->wq[0];
	struct sk_buff *skb;
	dma_addr_t pa;
	struct ethhdr *eth_hdr;
	struct vlan_ethhdr *vlan_hdr;
	struct fcoe_hdr *fcoe_hdr;
	struct fc_frame_header *fh;
	u32 tot_len, eth_hdr_len;
	int ret = 0;
	unsigned long flags;

	fh = fc_frame_header_get(fp);
	skb = fp_skb(fp);
	pa = dma_map_single(&fnic->pdev->dev, frame, frame_len, DMA_TO_DEVICE);

	if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ) &&
	    fcoe_ctlr_els_send(&fnic->ctlr, fnic->lport, skb))
		return 0;

	if (!fnic->vlan_hw_insert) {
		eth_hdr_len = sizeof(*vlan_hdr) + sizeof(*fcoe_hdr);
		vlan_hdr = skb_push(skb, eth_hdr_len);
		eth_hdr = (struct ethhdr *)vlan_hdr;
		vlan_hdr->h_vlan_proto = htons(ETH_P_8021Q);
		vlan_hdr->h_vlan_encapsulated_proto = htons(ETH_P_FCOE);
		vlan_hdr->h_vlan_TCI = htons(fnic->vlan_id);
		fcoe_hdr = (struct fcoe_hdr *)(vlan_hdr + 1);
	} else {
		eth_hdr_len = sizeof(*eth_hdr) + sizeof(*fcoe_hdr);
		eth_hdr = skb_push(skb, eth_hdr_len);
		eth_hdr->h_proto = htons(ETH_P_FCOE);
		fcoe_hdr = (struct fcoe_hdr *)(eth_hdr + 1);
	}

	if (fnic->ctlr.map_dest)
		fc_fcoe_set_mac(eth_hdr->h_dest, fh->fh_d_id);
	else
		memcpy(eth_hdr->h_dest, fnic->ctlr.dest_addr, ETH_ALEN);
	memcpy(eth_hdr->h_source, fnic->data_src_addr, ETH_ALEN);

	tot_len = skb->len;
	BUG_ON(tot_len % 4);

	memset(fcoe_hdr, 0, sizeof(*fcoe_hdr));
	fcoe_hdr->fcoe_sof = fr_sof(fp);
	if (FC_FCOE_VER)
		FC_FCOE_ENCAPS_VER(fcoe_hdr, FC_FCOE_VER);

	pa = dma_map_single(&fnic->pdev->dev, eth_hdr, tot_len, DMA_TO_DEVICE);
	if (dma_mapping_error(&fnic->pdev->dev, pa)) {
		ret = -ENOMEM;
		printk(KERN_ERR "DMA map failed with error %d\n", ret);
		goto free_skb_on_err;
	}

	if ((fnic_fc_trace_set_data(fnic->lport->host->host_no, FNIC_FC_SEND,
				(char *)eth_hdr, tot_len)) != 0) {
		printk(KERN_ERR "fnic ctlr frame trace error!!!");
	if ((fnic_fc_trace_set_data(fnic->fnic_num,
				FNIC_FC_SEND | 0x80, (char *) frame,
				frame_len)) != 0) {
		FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num,
					 "fnic ctlr frame trace error");
	}

	spin_lock_irqsave(&fnic->wq_lock[0], flags);

	if (!vnic_wq_desc_avail(wq)) {
		dma_unmap_single(&fnic->pdev->dev, pa, tot_len, DMA_TO_DEVICE);
		dma_unmap_single(&fnic->pdev->dev, pa, frame_len, DMA_TO_DEVICE);
		FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num,
					 "vnic work queue descriptor is not available");
		ret = -1;
		goto irq_restore;
		goto fnic_send_frame_end;
	}

	fnic_queue_wq_desc(wq, skb, pa, tot_len, fr_eof(fp),
			   0 /* hw inserts cos value */,
			   fnic->vlan_id, 1, 1, 1);
	/* hw inserts cos value */
	fnic_queue_wq_desc(wq, frame, pa, frame_len, FC_EOF_T,
					   0, fnic->vlan_id, 1, 1, 1);

irq_restore:
fnic_send_frame_end:
	spin_unlock_irqrestore(&fnic->wq_lock[0], flags);

free_skb_on_err:
	if (ret)
		dev_kfree_skb_any(fp_skb(fp));

	return ret;
}

/*
 * fnic_send
 * Routine to send a raw frame
/**
 * fdls_send_fcoe_frame - send a filled-in FC frame, filling in eth and FCoE
 *	info. This interface is used only in the non fast path. (login, fabric
 *	registrations etc.)
 *
 * @fnic:	fnic instance
 * @frame:	frame structure with FC payload filled in
 * @frame_size:	length of the frame to be sent
 * @srcmac:	source mac address
 * @dstmac:	destination mac address
 *
 * Called with the fnic lock held.
 */
int fnic_send(struct fc_lport *lp, struct fc_frame *fp)
static int
fdls_send_fcoe_frame(struct fnic *fnic, void *frame, int frame_size,
					 uint8_t *srcmac, uint8_t *dstmac)
{
	struct fnic *fnic = lport_priv(lp);
	unsigned long flags;
	struct ethhdr *pethhdr;
	struct fcoe_hdr *pfcoe_hdr;
	struct fnic_frame_list *frame_elem;
	int len = frame_size;
	int ret;
	struct fc_frame_header *fchdr = (struct fc_frame_header *) (frame +
			FNIC_ETH_FCOE_HDRS_OFFSET);

	if (fnic->in_remove) {
		dev_kfree_skb(fp_skb(fp));
		return -1;
	}
	pethhdr = (struct ethhdr *) frame;
	pethhdr->h_proto = cpu_to_be16(ETH_P_FCOE);

	memcpy(pethhdr->h_source, srcmac, ETH_ALEN);
	memcpy(pethhdr->h_dest, dstmac, ETH_ALEN);

	pfcoe_hdr = (struct fcoe_hdr *) (frame + sizeof(struct ethhdr));
	pfcoe_hdr->fcoe_sof = FC_SOF_I3;

	/*
	 * Queue frame if in a transitional state.
	 * This occurs while registering the Port_ID / MAC address after FLOGI.
	 */
	spin_lock_irqsave(&fnic->fnic_lock, flags);
	if (fnic->state != FNIC_IN_FC_MODE && fnic->state != FNIC_IN_ETH_MODE) {
		skb_queue_tail(&fnic->tx_queue, fp_skb(fp));
		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
	if ((fnic->state != FNIC_IN_FC_MODE)
		&& (fnic->state != FNIC_IN_ETH_MODE)) {
		frame_elem = mempool_alloc(fnic->frame_elem_pool,
						GFP_ATOMIC | __GFP_ZERO);
		if (!frame_elem) {
			FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num,
				 "Failed to allocate memory for frame elem");
			return -ENOMEM;
		}

		FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num,
			"Queueing FC frame: sid/did/type/oxid = 0x%x/0x%x/0x%x/0x%x\n",
			ntoh24(fchdr->fh_s_id), ntoh24(fchdr->fh_d_id),
			fchdr->fh_type, FNIC_STD_GET_OX_ID(fchdr));

		frame_elem->fp = frame;
		frame_elem->frame_len = len;
		list_add_tail(&frame_elem->links, &fnic->tx_queue);
		return 0;
	}
	spin_unlock_irqrestore(&fnic->fnic_lock, flags);

	return fnic_send_frame(fnic, fp);
	fnic_debug_dump_fc_frame(fnic, fchdr, frame_size, "Outgoing");

	ret = fnic_send_frame(fnic, frame, len);
	return ret;
}

void fnic_send_fcoe_frame(struct fnic_iport_s *iport, void *frame,
						 int frame_size)
{
	struct fnic *fnic = iport->fnic;
	uint8_t *dstmac, *srcmac;

	/* If module unload is in-progress, don't send */
	if (fnic->in_remove)
		return;

	if (iport->fabric.flags & FNIC_FDLS_FPMA_LEARNT) {
		srcmac = iport->fpma;
		dstmac = iport->fcfmac;
	} else {
		srcmac = iport->hwmac;
		dstmac = FCOE_ALL_FCF_MAC;
	}

	fdls_send_fcoe_frame(fnic, frame, frame_size, srcmac, dstmac);
}

int
fnic_send_fip_frame(struct fnic_iport_s *iport, void *frame,
					int frame_size)
{
	struct fnic *fnic = iport->fnic;

	if (fnic->in_remove)
		return -1;

	return fnic_send_frame(fnic, frame, frame_size);
}

/**
@@ -1193,13 +1296,65 @@ int fnic_send(struct fc_lport *lp, struct fc_frame *fp)
void fnic_flush_tx(struct work_struct *work)
{
	struct fnic *fnic = container_of(work, struct fnic, flush_work);
	struct sk_buff *skb;
	struct fc_frame *fp;
	struct fnic_frame_list *cur_frame, *next;

	while ((skb = skb_dequeue(&fnic->tx_queue))) {
		fp = (struct fc_frame *)skb;
		fnic_send_frame(fnic, fp);
	FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num,
				 "Flush queued frames");

	list_for_each_entry_safe(cur_frame, next, &fnic->tx_queue, links) {
		fp = cur_frame->fp;
		list_del(&cur_frame->links);
		fnic_send_frame(fnic, fp, cur_frame->frame_len);
		mempool_free(cur_frame, fnic->frame_elem_pool);
	}
}

int
fnic_fdls_register_portid(struct fnic_iport_s *iport, u32 port_id,
						  void *fp)
{
	struct fnic *fnic = iport->fnic;
	struct ethhdr *ethhdr;
	int ret;

	FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num,
				 "Setting port id: 0x%x fp: 0x%p fnic state: %d", port_id,
				 fp, fnic->state);

	if (fp) {
		ethhdr = (struct ethhdr *) fp;
		vnic_dev_add_addr(fnic->vdev, ethhdr->h_dest);
	}

	/* Change state to reflect transition to FC mode */
	if (fnic->state == FNIC_IN_ETH_MODE || fnic->state == FNIC_IN_FC_MODE)
		fnic->state = FNIC_IN_ETH_TRANS_FC_MODE;
	else {
		FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num,
			 "Unexpected fnic state while processing FLOGI response\n");
		return -1;
	}

	/*
	 * Send FLOGI registration to firmware to set up FC mode.
	 * The new address will be set up when registration completes.
	 */
	ret = fnic_flogi_reg_handler(fnic, port_id);
	if (ret < 0) {
		FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num,
					 "FLOGI registration error ret: %d fnic state: %d\n",
					 ret, fnic->state);
		if (fnic->state == FNIC_IN_ETH_TRANS_FC_MODE)
			fnic->state = FNIC_IN_ETH_MODE;

		return -1;
	}
	iport->fabric.flags |= FNIC_FDLS_FPMA_LEARNT;

	FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num,
				 "FLOGI registration success\n");
	return 0;
}

/**
@@ -1240,6 +1395,17 @@ static void fnic_set_eth_mode(struct fnic *fnic)
	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
}

void fnic_free_txq(struct list_head *head)
{
	struct fnic_frame_list *cur_frame, *next;

	list_for_each_entry_safe(cur_frame, next, head, links) {
		list_del(&cur_frame->links);
		kfree(cur_frame->fp);
		kfree(cur_frame);
	}
}

static void fnic_wq_complete_frame_send(struct vnic_wq *wq,
					struct cq_desc *cq_desc,
					struct vnic_wq_buf *buf, void *opaque)
@@ -1319,88 +1485,3 @@ void fnic_fcoe_reset_vlans(struct fnic *fnic)
	spin_unlock_irqrestore(&fnic->vlans_lock, flags);
}
void fnic_handle_fip_timer(struct fnic *fnic)
{
	unsigned long flags;
	struct fcoe_vlan *vlan;
	struct fnic_stats *fnic_stats = &fnic->fnic_stats;
	u64 sol_time;

	spin_lock_irqsave(&fnic->fnic_lock, flags);
	if (fnic->stop_rx_link_events) {
		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
		return;
	}
	spin_unlock_irqrestore(&fnic->fnic_lock, flags);

	if (fnic->ctlr.mode == FIP_MODE_NON_FIP)
		return;

	spin_lock_irqsave(&fnic->vlans_lock, flags);
	if (list_empty(&fnic->vlans)) {
		spin_unlock_irqrestore(&fnic->vlans_lock, flags);
		/* no vlans available, try again */
		if (unlikely(fnic_log_level & FNIC_FCS_LOGGING))
			if (printk_ratelimit())
				shost_printk(KERN_DEBUG, fnic->lport->host,
						"Start VLAN Discovery\n");
		fnic_event_enq(fnic, FNIC_EVT_START_VLAN_DISC);
		return;
	}

	vlan = list_first_entry(&fnic->vlans, struct fcoe_vlan, list);
	FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num,
		  "fip_timer: vlan %d state %d sol_count %d\n",
		  vlan->vid, vlan->state, vlan->sol_count);
	switch (vlan->state) {
	case FIP_VLAN_USED:
		FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num,
			  "FIP VLAN is selected for FC transaction\n");
		spin_unlock_irqrestore(&fnic->vlans_lock, flags);
		break;
	case FIP_VLAN_FAILED:
		spin_unlock_irqrestore(&fnic->vlans_lock, flags);
		/* if all vlans are in failed state, restart vlan disc */
		if (unlikely(fnic_log_level & FNIC_FCS_LOGGING))
			if (printk_ratelimit())
				shost_printk(KERN_DEBUG, fnic->lport->host,
					  "Start VLAN Discovery\n");
		fnic_event_enq(fnic, FNIC_EVT_START_VLAN_DISC);
		break;
	case FIP_VLAN_SENT:
		if (vlan->sol_count >= FCOE_CTLR_MAX_SOL) {
			/*
			 * no response on this vlan, remove  from the list.
			 * Try the next vlan
			 */
			FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num,
				  "Dequeue this VLAN ID %d from list\n",
				  vlan->vid);
			list_del(&vlan->list);
			kfree(vlan);
			vlan = NULL;
			if (list_empty(&fnic->vlans)) {
				/* we exhausted all vlans, restart vlan disc */
				spin_unlock_irqrestore(&fnic->vlans_lock,
							flags);
				FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num,
					  "fip_timer: vlan list empty, "
					  "trigger vlan disc\n");
				fnic_event_enq(fnic, FNIC_EVT_START_VLAN_DISC);
				return;
			}
			/* check the next vlan */
			vlan = list_first_entry(&fnic->vlans, struct fcoe_vlan,
							list);
			fnic->set_vlan(fnic, vlan->vid);
			vlan->state = FIP_VLAN_SENT; /* sent now */
		}
		spin_unlock_irqrestore(&fnic->vlans_lock, flags);
		atomic64_inc(&fnic_stats->vlan_stats.sol_expiry_count);
		vlan->sol_count++;
		sol_time = jiffies + msecs_to_jiffies
					(FCOE_CTLR_START_DELAY);
		mod_timer(&fnic->fip_timer, round_jiffies(sol_time));
		break;
	}
}
+0 −1
Original line number Diff line number Diff line
@@ -402,7 +402,6 @@ int fnic_send_fip_frame(struct fnic_iport_s *iport,
	void *frame, int frame_size);
void fnic_fdls_learn_fcoe_macs(struct fnic_iport_s *iport, void *rx_frame,
	uint8_t *fcid);

void fnic_fdls_add_tport(struct fnic_iport_s *iport,
		struct fnic_tport_s *tport, unsigned long flags);
void fnic_fdls_remove_tport(struct fnic_iport_s *iport,
Loading