Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 51e569aa authored by Krishna Gudipati's avatar Krishna Gudipati Committed by James Bottomley
Browse files

[SCSI] bfa: Added support to obtain SFP info.



- Added SFP sub-module to BFA.
- Added interface to collect sfp media info and sfp speed.

Signed-off-by: default avatarKrishna Gudipati <kgudipat@brocade.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 148d6103
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -122,6 +122,16 @@ bfa_com_cee_attach(struct bfa_s *bfa)
	bfa_cee_mem_claim(cee, cee_dma->kva_curp, cee_dma->dma_curp);
}

static void
bfa_com_sfp_attach(struct bfa_s *bfa)
{
	struct bfa_sfp_s	*sfp = BFA_SFP_MOD(bfa);
	struct bfa_mem_dma_s	*sfp_dma = BFA_MEM_SFP_DMA(bfa);

	bfa_sfp_attach(sfp, &bfa->ioc, bfa, bfa->trcmod);
	bfa_sfp_memclaim(sfp, sfp_dma->kva_curp, sfp_dma->dma_curp);
}

/*
 * BFA IOC FC related definitions
 */
@@ -1360,6 +1370,7 @@ bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo,
	struct bfa_mem_dma_s *port_dma = BFA_MEM_PORT_DMA(bfa);
	struct bfa_mem_dma_s *ablk_dma = BFA_MEM_ABLK_DMA(bfa);
	struct bfa_mem_dma_s *cee_dma = BFA_MEM_CEE_DMA(bfa);
	struct bfa_mem_dma_s *sfp_dma = BFA_MEM_SFP_DMA(bfa);

	WARN_ON((cfg == NULL) || (meminfo == NULL));

@@ -1378,6 +1389,7 @@ bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo,
	bfa_mem_dma_setup(meminfo, port_dma, bfa_port_meminfo());
	bfa_mem_dma_setup(meminfo, ablk_dma, bfa_ablk_meminfo());
	bfa_mem_dma_setup(meminfo, cee_dma, bfa_cee_meminfo());
	bfa_mem_dma_setup(meminfo, sfp_dma, bfa_sfp_meminfo());
}

/*
@@ -1446,6 +1458,7 @@ bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
	bfa_com_port_attach(bfa);
	bfa_com_ablk_attach(bfa);
	bfa_com_cee_attach(bfa);
	bfa_com_sfp_attach(bfa);
}

/*
+266 −0
Original line number Diff line number Diff line
@@ -130,6 +130,7 @@ enum bfa_status {
	BFA_STATUS_ETIMER	= 5,	/*  Timer expired - Retry, if persists,
					 *  contact support */
	BFA_STATUS_EPROTOCOL	= 6,	/*  Protocol error */
	BFA_STATUS_SFP_UNSUPP	= 10,	/*  Unsupported SFP - Replace SFP */
	BFA_STATUS_UNKNOWN_VFID = 11,	/*  VF_ID not found */
	BFA_STATUS_DEVBUSY	= 13,	/*  Device busy - Retry operation */
	BFA_STATUS_UNKNOWN_LWWN = 18,	/*  LPORT PWWN not found */
@@ -150,9 +151,11 @@ enum bfa_status {
	BFA_STATUS_DIAG_BUSY	= 71,	/*  diag busy */
	BFA_STATUS_ENOFSAVE	= 78,	/*  No saved firmware trace */
	BFA_STATUS_IOC_DISABLED = 82,   /* IOC is already disabled */
	BFA_STATUS_NO_SFP_DEV = 89,	/* No SFP device check or replace SFP */
	BFA_STATUS_INVALID_MAC  = 134, /*  Invalid MAC address */
	BFA_STATUS_PBC		= 154, /*  Operation not allowed for pre-boot
					*  configuration */
	BFA_STATUS_SFP_NOT_READY = 159,	/* SFP info is not ready. Retry */
	BFA_STATUS_TRUNK_ENABLED = 164, /* Trunk is already enabled on
					 * this adapter */
	BFA_STATUS_TRUNK_DISABLED  = 165, /* Trunking is disabled on
@@ -559,6 +562,269 @@ struct bfa_ablk_cfg_inst_s {
struct bfa_ablk_cfg_s {
	struct bfa_ablk_cfg_inst_s	inst[BFA_ABLK_MAX];
};


/*
 *	SFP module specific
 */
#define SFP_DIAGMON_SIZE	10 /* num bytes of diag monitor data */

enum bfa_defs_sfp_media_e {
	BFA_SFP_MEDIA_UNKNOWN	= 0x00,
	BFA_SFP_MEDIA_CU	= 0x01,
	BFA_SFP_MEDIA_LW	= 0x02,
	BFA_SFP_MEDIA_SW	= 0x03,
	BFA_SFP_MEDIA_EL	= 0x04,
	BFA_SFP_MEDIA_UNSUPPORT	= 0x05,
};

/*
 * values for xmtr_tech above
 */
enum {
	SFP_XMTR_TECH_CU = (1 << 0),	/* copper FC-BaseT */
	SFP_XMTR_TECH_CP = (1 << 1),	/* copper passive */
	SFP_XMTR_TECH_CA = (1 << 2),	/* copper active */
	SFP_XMTR_TECH_LL = (1 << 3),	/* longwave laser */
	SFP_XMTR_TECH_SL = (1 << 4),	/* shortwave laser w/ OFC */
	SFP_XMTR_TECH_SN = (1 << 5),	/* shortwave laser w/o OFC */
	SFP_XMTR_TECH_EL_INTRA = (1 << 6), /* elec intra-enclosure */
	SFP_XMTR_TECH_EL_INTER = (1 << 7), /* elec inter-enclosure */
	SFP_XMTR_TECH_LC = (1 << 8),	/* longwave laser */
	SFP_XMTR_TECH_SA = (1 << 9)
};

/*
 * Serial ID: Data Fields -- Address A0h
 * Basic ID field total 64 bytes
 */
struct sfp_srlid_base_s {
	u8	id;		/* 00: Identifier */
	u8	extid;		/* 01: Extended Identifier */
	u8	connector;	/* 02: Connector */
	u8	xcvr[8];	/* 03-10: Transceiver */
	u8	encoding;	/* 11: Encoding */
	u8	br_norm;	/* 12: BR, Nominal */
	u8	rate_id;	/* 13: Rate Identifier */
	u8	len_km;		/* 14: Length single mode km */
	u8	len_100m;	/* 15: Length single mode 100m */
	u8	len_om2;	/* 16: Length om2 fiber 10m */
	u8	len_om1;	/* 17: Length om1 fiber 10m */
	u8	len_cu;		/* 18: Length copper 1m */
	u8	len_om3;	/* 19: Length om3 fiber 10m */
	u8	vendor_name[16];/* 20-35 */
	u8	unalloc1;
	u8	vendor_oui[3];	/* 37-39 */
	u8	vendor_pn[16];	/* 40-55 */
	u8	vendor_rev[4];	/* 56-59 */
	u8	wavelen[2];	/* 60-61 */
	u8	unalloc2;
	u8	cc_base;	/* 63: check code for base id field */
};

/*
 * Serial ID: Data Fields -- Address A0h
 * Extended id field total 32 bytes
 */
struct sfp_srlid_ext_s {
	u8	options[2];
	u8	br_max;
	u8	br_min;
	u8	vendor_sn[16];
	u8	date_code[8];
	u8	diag_mon_type;  /* 92: Diagnostic Monitoring type */
	u8	en_options;
	u8	sff_8472;
	u8	cc_ext;
};

/*
 * Diagnostic: Data Fields -- Address A2h
 * Diagnostic and control/status base field total 96 bytes
 */
struct sfp_diag_base_s {
	/*
	 * Alarm and warning Thresholds 40 bytes
	 */
	u8	temp_high_alarm[2]; /* 00-01 */
	u8	temp_low_alarm[2];  /* 02-03 */
	u8	temp_high_warning[2];   /* 04-05 */
	u8	temp_low_warning[2];    /* 06-07 */

	u8	volt_high_alarm[2]; /* 08-09 */
	u8	volt_low_alarm[2];  /* 10-11 */
	u8	volt_high_warning[2];   /* 12-13 */
	u8	volt_low_warning[2];    /* 14-15 */

	u8	bias_high_alarm[2]; /* 16-17 */
	u8	bias_low_alarm[2];  /* 18-19 */
	u8	bias_high_warning[2];   /* 20-21 */
	u8	bias_low_warning[2];    /* 22-23 */

	u8	tx_pwr_high_alarm[2];   /* 24-25 */
	u8	tx_pwr_low_alarm[2];    /* 26-27 */
	u8	tx_pwr_high_warning[2]; /* 28-29 */
	u8	tx_pwr_low_warning[2];  /* 30-31 */

	u8	rx_pwr_high_alarm[2];   /* 32-33 */
	u8	rx_pwr_low_alarm[2];    /* 34-35 */
	u8	rx_pwr_high_warning[2]; /* 36-37 */
	u8	rx_pwr_low_warning[2];  /* 38-39 */

	u8	unallocate_1[16];

	/*
	 * ext_cal_const[36]
	 */
	u8	rx_pwr[20];
	u8	tx_i[4];
	u8	tx_pwr[4];
	u8	temp[4];
	u8	volt[4];
	u8	unallocate_2[3];
	u8	cc_dmi;
};

/*
 * Diagnostic: Data Fields -- Address A2h
 * Diagnostic and control/status extended field total 24 bytes
 */
struct sfp_diag_ext_s {
	u8	diag[SFP_DIAGMON_SIZE];
	u8	unalloc1[4];
	u8	status_ctl;
	u8	rsvd;
	u8	alarm_flags[2];
	u8	unalloc2[2];
	u8	warning_flags[2];
	u8	ext_status_ctl[2];
};

struct sfp_mem_s {
	struct sfp_srlid_base_s	srlid_base;
	struct sfp_srlid_ext_s	srlid_ext;
	struct sfp_diag_base_s	diag_base;
	struct sfp_diag_ext_s	diag_ext;
};

/*
 * transceiver codes (SFF-8472 Rev 10.2 Table 3.5)
 */
union sfp_xcvr_e10g_code_u {
	u8		b;
	struct {
#ifdef __BIGENDIAN
		u8	e10g_unall:1;   /* 10G Ethernet compliance */
		u8	e10g_lrm:1;
		u8	e10g_lr:1;
		u8	e10g_sr:1;
		u8	ib_sx:1;    /* Infiniband compliance */
		u8	ib_lx:1;
		u8	ib_cu_a:1;
		u8	ib_cu_p:1;
#else
		u8	ib_cu_p:1;
		u8	ib_cu_a:1;
		u8	ib_lx:1;
		u8	ib_sx:1;    /* Infiniband compliance */
		u8	e10g_sr:1;
		u8	e10g_lr:1;
		u8	e10g_lrm:1;
		u8	e10g_unall:1;   /* 10G Ethernet compliance */
#endif
	} r;
};

union sfp_xcvr_so1_code_u {
	u8		b;
	struct {
		u8	escon:2;    /* ESCON compliance code */
		u8	oc192_reach:1;  /* SONET compliance code */
		u8	so_reach:2;
		u8	oc48_reach:3;
	} r;
};

union sfp_xcvr_so2_code_u {
	u8		b;
	struct {
		u8	reserved:1;
		u8	oc12_reach:3;   /* OC12 reach */
		u8	reserved1:1;
		u8	oc3_reach:3;    /* OC3 reach */
	} r;
};

union sfp_xcvr_eth_code_u {
	u8		b;
	struct {
		u8	base_px:1;
		u8	base_bx10:1;
		u8	e100base_fx:1;
		u8	e100base_lx:1;
		u8	e1000base_t:1;
		u8	e1000base_cx:1;
		u8	e1000base_lx:1;
		u8	e1000base_sx:1;
	} r;
};

struct sfp_xcvr_fc1_code_s {
	u8	link_len:5; /* FC link length */
	u8	xmtr_tech2:3;
	u8	xmtr_tech1:7;   /* FC transmitter technology */
	u8	reserved1:1;
};

union sfp_xcvr_fc2_code_u {
	u8		b;
	struct {
		u8	tw_media:1; /* twin axial pair (tw) */
		u8	tp_media:1; /* shielded twisted pair (sp) */
		u8	mi_media:1; /* miniature coax (mi) */
		u8	tv_media:1; /* video coax (tv) */
		u8	m6_media:1; /* multimode, 62.5m (m6) */
		u8	m5_media:1; /* multimode, 50m (m5) */
		u8	reserved:1;
		u8	sm_media:1; /* single mode (sm) */
	} r;
};

union sfp_xcvr_fc3_code_u {
	u8		b;
	struct {
#ifdef __BIGENDIAN
		u8	rsv4:1;
		u8	mb800:1;    /* 800 Mbytes/sec */
		u8	mb1600:1;   /* 1600 Mbytes/sec */
		u8	mb400:1;    /* 400 Mbytes/sec */
		u8	rsv2:1;
		u8	mb200:1;    /* 200 Mbytes/sec */
		u8	rsv1:1;
		u8	mb100:1;    /* 100 Mbytes/sec */
#else
		u8	mb100:1;    /* 100 Mbytes/sec */
		u8	rsv1:1;
		u8	mb200:1;    /* 200 Mbytes/sec */
		u8	rsv2:1;
		u8	mb400:1;    /* 400 Mbytes/sec */
		u8	mb1600:1;   /* 1600 Mbytes/sec */
		u8	mb800:1;    /* 800 Mbytes/sec */
		u8	rsv4:1;
#endif
	} r;
};

struct sfp_xcvr_s {
	union sfp_xcvr_e10g_code_u	e10g;
	union sfp_xcvr_so1_code_u	so1;
	union sfp_xcvr_so2_code_u	so2;
	union sfp_xcvr_eth_code_u	eth;
	struct sfp_xcvr_fc1_code_s	fc1;
	union sfp_xcvr_fc2_code_u	fc2;
	union sfp_xcvr_fc3_code_u	fc3;
};

#pragma pack()

#endif /* __BFA_DEFS_H__ */
+457 −0
Original line number Diff line number Diff line
@@ -3364,3 +3364,460 @@ bfa_ablk_optrom_dis(struct bfa_ablk_s *ablk, bfa_ablk_cbfn_t cbfn, void *cbarg)

	return BFA_STATUS_OK;
}

/*
 *	SFP module specific
 */

/* forward declarations */
static void bfa_sfp_getdata_send(struct bfa_sfp_s *sfp);
static void bfa_sfp_media_get(struct bfa_sfp_s *sfp);
static bfa_status_t bfa_sfp_speed_valid(struct bfa_sfp_s *sfp,
				enum bfa_port_speed portspeed);

static void
bfa_cb_sfp_show(struct bfa_sfp_s *sfp)
{
	bfa_trc(sfp, sfp->lock);
	if (sfp->cbfn)
		sfp->cbfn(sfp->cbarg, sfp->status);
	sfp->lock = 0;
	sfp->cbfn = NULL;
}

static void
bfa_cb_sfp_state_query(struct bfa_sfp_s *sfp)
{
	bfa_trc(sfp, sfp->portspeed);
	if (sfp->media) {
		bfa_sfp_media_get(sfp);
		if (sfp->state_query_cbfn)
			sfp->state_query_cbfn(sfp->state_query_cbarg,
					sfp->status);
			sfp->media = NULL;
		}

		if (sfp->portspeed) {
			sfp->status = bfa_sfp_speed_valid(sfp, sfp->portspeed);
			if (sfp->state_query_cbfn)
				sfp->state_query_cbfn(sfp->state_query_cbarg,
						sfp->status);
				sfp->portspeed = BFA_PORT_SPEED_UNKNOWN;
		}

		sfp->state_query_lock = 0;
		sfp->state_query_cbfn = NULL;
}

/*
 *	IOC event handler.
 */
static void
bfa_sfp_notify(void *sfp_arg, enum bfa_ioc_event_e event)
{
	struct bfa_sfp_s *sfp = sfp_arg;

	bfa_trc(sfp, event);
	bfa_trc(sfp, sfp->lock);
	bfa_trc(sfp, sfp->state_query_lock);

	switch (event) {
	case BFA_IOC_E_DISABLED:
	case BFA_IOC_E_FAILED:
		if (sfp->lock) {
			sfp->status = BFA_STATUS_IOC_FAILURE;
			bfa_cb_sfp_show(sfp);
		}

		if (sfp->state_query_lock) {
			sfp->status = BFA_STATUS_IOC_FAILURE;
			bfa_cb_sfp_state_query(sfp);
		}
		break;

	default:
		break;
	}
}

/*
 *	SFP get data send
 */
static void
bfa_sfp_getdata_send(struct bfa_sfp_s *sfp)
{
	struct bfi_sfp_req_s *req = (struct bfi_sfp_req_s *)sfp->mbcmd.msg;

	bfa_trc(sfp, req->memtype);

	/* build host command */
	bfi_h2i_set(req->mh, BFI_MC_SFP, BFI_SFP_H2I_SHOW,
			bfa_ioc_portid(sfp->ioc));

	/* send mbox cmd */
	bfa_ioc_mbox_queue(sfp->ioc, &sfp->mbcmd);
}

/*
 *	SFP is valid, read sfp data
 */
static void
bfa_sfp_getdata(struct bfa_sfp_s *sfp, enum bfi_sfp_mem_e memtype)
{
	struct bfi_sfp_req_s *req = (struct bfi_sfp_req_s *)sfp->mbcmd.msg;

	WARN_ON(sfp->lock != 0);
	bfa_trc(sfp, sfp->state);

	sfp->lock = 1;
	sfp->memtype = memtype;
	req->memtype = memtype;

	/* Setup SG list */
	bfa_alen_set(&req->alen, sizeof(struct sfp_mem_s), sfp->dbuf_pa);

	bfa_sfp_getdata_send(sfp);
}

/*
 * SFP show complete
 */
static void
bfa_sfp_show_comp(struct bfa_sfp_s *sfp, struct bfi_mbmsg_s *msg)
{
	struct bfi_sfp_rsp_s *rsp = (struct bfi_sfp_rsp_s *) msg;

	if (!sfp->lock) {
		/*
		 * receiving response after ioc failure
		 */
		bfa_trc(sfp, sfp->lock);
		return;
	}

	bfa_trc(sfp, rsp->status);
	if (rsp->status == BFA_STATUS_OK) {
		sfp->data_valid = 1;
		if (sfp->state == BFA_SFP_STATE_VALID)
			sfp->status = BFA_STATUS_OK;
		else if (sfp->state == BFA_SFP_STATE_UNSUPPORT)
			sfp->status = BFA_STATUS_SFP_UNSUPP;
		else
			bfa_trc(sfp, sfp->state);
	} else {
		sfp->data_valid = 0;
		sfp->status = rsp->status;
		/* sfpshow shouldn't change sfp state */
	}

	bfa_trc(sfp, sfp->memtype);
	if (sfp->memtype == BFI_SFP_MEM_DIAGEXT) {
		bfa_trc(sfp, sfp->data_valid);
		if (sfp->data_valid) {
			u32	size = sizeof(struct sfp_mem_s);
			u8 *des = (u8 *) &(sfp->sfpmem->srlid_base);
			memcpy(des, sfp->dbuf_kva, size);
		}
		/*
		 * Queue completion callback.
		 */
		bfa_cb_sfp_show(sfp);
	} else
		sfp->lock = 0;

	bfa_trc(sfp, sfp->state_query_lock);
	if (sfp->state_query_lock) {
		sfp->state = rsp->state;
		/* Complete callback */
		bfa_cb_sfp_state_query(sfp);
	}
}

/*
 *	SFP query fw sfp state
 */
static void
bfa_sfp_state_query(struct bfa_sfp_s *sfp)
{
	struct bfi_sfp_req_s *req = (struct bfi_sfp_req_s *)sfp->mbcmd.msg;

	/* Should not be doing query if not in _INIT state */
	WARN_ON(sfp->state != BFA_SFP_STATE_INIT);
	WARN_ON(sfp->state_query_lock != 0);
	bfa_trc(sfp, sfp->state);

	sfp->state_query_lock = 1;
	req->memtype = 0;

	if (!sfp->lock)
		bfa_sfp_getdata(sfp, BFI_SFP_MEM_ALL);
}

static void
bfa_sfp_media_get(struct bfa_sfp_s *sfp)
{
	enum bfa_defs_sfp_media_e *media = sfp->media;

	*media = BFA_SFP_MEDIA_UNKNOWN;

	if (sfp->state == BFA_SFP_STATE_UNSUPPORT)
		*media = BFA_SFP_MEDIA_UNSUPPORT;
	else if (sfp->state == BFA_SFP_STATE_VALID) {
		union sfp_xcvr_e10g_code_u e10g;
		struct sfp_mem_s *sfpmem = (struct sfp_mem_s *)sfp->dbuf_kva;
		u16 xmtr_tech = (sfpmem->srlid_base.xcvr[4] & 0x3) << 7 |
				(sfpmem->srlid_base.xcvr[5] >> 1);

		e10g.b = sfpmem->srlid_base.xcvr[0];
		bfa_trc(sfp, e10g.b);
		bfa_trc(sfp, xmtr_tech);
		/* check fc transmitter tech */
		if ((xmtr_tech & SFP_XMTR_TECH_CU) ||
		    (xmtr_tech & SFP_XMTR_TECH_CP) ||
		    (xmtr_tech & SFP_XMTR_TECH_CA))
			*media = BFA_SFP_MEDIA_CU;
		else if ((xmtr_tech & SFP_XMTR_TECH_EL_INTRA) ||
			 (xmtr_tech & SFP_XMTR_TECH_EL_INTER))
			*media = BFA_SFP_MEDIA_EL;
		else if ((xmtr_tech & SFP_XMTR_TECH_LL) ||
			 (xmtr_tech & SFP_XMTR_TECH_LC))
			*media = BFA_SFP_MEDIA_LW;
		else if ((xmtr_tech & SFP_XMTR_TECH_SL) ||
			 (xmtr_tech & SFP_XMTR_TECH_SN) ||
			 (xmtr_tech & SFP_XMTR_TECH_SA))
			*media = BFA_SFP_MEDIA_SW;
		/* Check 10G Ethernet Compilance code */
		else if (e10g.b & 0x10)
			*media = BFA_SFP_MEDIA_SW;
		else if (e10g.b & 0x60)
			*media = BFA_SFP_MEDIA_LW;
		else if (e10g.r.e10g_unall & 0x80)
			*media = BFA_SFP_MEDIA_UNKNOWN;
		else
			bfa_trc(sfp, 0);
	} else
		bfa_trc(sfp, sfp->state);
}

static bfa_status_t
bfa_sfp_speed_valid(struct bfa_sfp_s *sfp, enum bfa_port_speed portspeed)
{
	struct sfp_mem_s *sfpmem = (struct sfp_mem_s *)sfp->dbuf_kva;
	struct sfp_xcvr_s *xcvr = (struct sfp_xcvr_s *) sfpmem->srlid_base.xcvr;
	union sfp_xcvr_fc3_code_u fc3 = xcvr->fc3;
	union sfp_xcvr_e10g_code_u e10g = xcvr->e10g;

	if (portspeed == BFA_PORT_SPEED_10GBPS) {
		if (e10g.r.e10g_sr || e10g.r.e10g_lr)
			return BFA_STATUS_OK;
		else {
			bfa_trc(sfp, e10g.b);
			return BFA_STATUS_UNSUPP_SPEED;
		}
	}
	if (((portspeed & BFA_PORT_SPEED_16GBPS) && fc3.r.mb1600) ||
	    ((portspeed & BFA_PORT_SPEED_8GBPS) && fc3.r.mb800) ||
	    ((portspeed & BFA_PORT_SPEED_4GBPS) && fc3.r.mb400) ||
	    ((portspeed & BFA_PORT_SPEED_2GBPS) && fc3.r.mb200) ||
	    ((portspeed & BFA_PORT_SPEED_1GBPS) && fc3.r.mb100))
		return BFA_STATUS_OK;
	else {
		bfa_trc(sfp, portspeed);
		bfa_trc(sfp, fc3.b);
		bfa_trc(sfp, e10g.b);
		return BFA_STATUS_UNSUPP_SPEED;
	}
}

/*
 *	SFP hmbox handler
 */
void
bfa_sfp_intr(void *sfparg, struct bfi_mbmsg_s *msg)
{
	struct bfa_sfp_s *sfp = sfparg;

	switch (msg->mh.msg_id) {
	case BFI_SFP_I2H_SHOW:
		bfa_sfp_show_comp(sfp, msg);
		break;

	case BFI_SFP_I2H_SCN:
		bfa_trc(sfp, msg->mh.msg_id);
		break;

	default:
		bfa_trc(sfp, msg->mh.msg_id);
		WARN_ON(1);
	}
}

/*
 *	Return DMA memory needed by sfp module.
 */
u32
bfa_sfp_meminfo(void)
{
	return BFA_ROUNDUP(sizeof(struct sfp_mem_s), BFA_DMA_ALIGN_SZ);
}

/*
 *	Attach virtual and physical memory for SFP.
 */
void
bfa_sfp_attach(struct bfa_sfp_s *sfp, struct bfa_ioc_s *ioc, void *dev,
		struct bfa_trc_mod_s *trcmod)
{
	sfp->dev = dev;
	sfp->ioc = ioc;
	sfp->trcmod = trcmod;

	sfp->cbfn = NULL;
	sfp->cbarg = NULL;
	sfp->sfpmem = NULL;
	sfp->lock = 0;
	sfp->data_valid = 0;
	sfp->state = BFA_SFP_STATE_INIT;
	sfp->state_query_lock = 0;
	sfp->state_query_cbfn = NULL;
	sfp->state_query_cbarg = NULL;
	sfp->media = NULL;
	sfp->portspeed = BFA_PORT_SPEED_UNKNOWN;
	sfp->is_elb = BFA_FALSE;

	bfa_ioc_mbox_regisr(sfp->ioc, BFI_MC_SFP, bfa_sfp_intr, sfp);
	bfa_q_qe_init(&sfp->ioc_notify);
	bfa_ioc_notify_init(&sfp->ioc_notify, bfa_sfp_notify, sfp);
	list_add_tail(&sfp->ioc_notify.qe, &sfp->ioc->notify_q);
}

/*
 *	Claim Memory for SFP
 */
void
bfa_sfp_memclaim(struct bfa_sfp_s *sfp, u8 *dm_kva, u64 dm_pa)
{
	sfp->dbuf_kva   = dm_kva;
	sfp->dbuf_pa    = dm_pa;
	memset(sfp->dbuf_kva, 0, sizeof(struct sfp_mem_s));

	dm_kva += BFA_ROUNDUP(sizeof(struct sfp_mem_s), BFA_DMA_ALIGN_SZ);
	dm_pa += BFA_ROUNDUP(sizeof(struct sfp_mem_s), BFA_DMA_ALIGN_SZ);
}

/*
 * Show SFP eeprom content
 *
 * @param[in] sfp   - bfa sfp module
 *
 * @param[out] sfpmem - sfp eeprom data
 *
 */
bfa_status_t
bfa_sfp_show(struct bfa_sfp_s *sfp, struct sfp_mem_s *sfpmem,
		bfa_cb_sfp_t cbfn, void *cbarg)
{

	if (!bfa_ioc_is_operational(sfp->ioc)) {
		bfa_trc(sfp, 0);
		return BFA_STATUS_IOC_NON_OP;
	}

	if (sfp->lock) {
		bfa_trc(sfp, 0);
		return BFA_STATUS_DEVBUSY;
	}

	sfp->cbfn = cbfn;
	sfp->cbarg = cbarg;
	sfp->sfpmem = sfpmem;

	bfa_sfp_getdata(sfp, BFI_SFP_MEM_DIAGEXT);
	return BFA_STATUS_OK;
}

/*
 * Return SFP Media type
 *
 * @param[in] sfp   - bfa sfp module
 *
 * @param[out] media - port speed from user
 *
 */
bfa_status_t
bfa_sfp_media(struct bfa_sfp_s *sfp, enum bfa_defs_sfp_media_e *media,
		bfa_cb_sfp_t cbfn, void *cbarg)
{
	if (!bfa_ioc_is_operational(sfp->ioc)) {
		bfa_trc(sfp, 0);
		return BFA_STATUS_IOC_NON_OP;
	}

	sfp->media = media;
	if (sfp->state == BFA_SFP_STATE_INIT) {
		if (sfp->state_query_lock) {
			bfa_trc(sfp, 0);
			return BFA_STATUS_DEVBUSY;
		} else {
			sfp->state_query_cbfn = cbfn;
			sfp->state_query_cbarg = cbarg;
			bfa_sfp_state_query(sfp);
			return BFA_STATUS_SFP_NOT_READY;
		}
	}

	bfa_sfp_media_get(sfp);
	return BFA_STATUS_OK;
}

/*
 * Check if user set port speed is allowed by the SFP
 *
 * @param[in] sfp   - bfa sfp module
 * @param[in] portspeed - port speed from user
 *
 */
bfa_status_t
bfa_sfp_speed(struct bfa_sfp_s *sfp, enum bfa_port_speed portspeed,
		bfa_cb_sfp_t cbfn, void *cbarg)
{
	WARN_ON(portspeed == BFA_PORT_SPEED_UNKNOWN);

	if (!bfa_ioc_is_operational(sfp->ioc))
		return BFA_STATUS_IOC_NON_OP;

	/* For Mezz card, all speed is allowed */
	if (bfa_mfg_is_mezz(sfp->ioc->attr->card_type))
		return BFA_STATUS_OK;

	/* Check SFP state */
	sfp->portspeed = portspeed;
	if (sfp->state == BFA_SFP_STATE_INIT) {
		if (sfp->state_query_lock) {
			bfa_trc(sfp, 0);
			return BFA_STATUS_DEVBUSY;
		} else {
			sfp->state_query_cbfn = cbfn;
			sfp->state_query_cbarg = cbarg;
			bfa_sfp_state_query(sfp);
			return BFA_STATUS_SFP_NOT_READY;
		}
	}

	if (sfp->state == BFA_SFP_STATE_REMOVED ||
	    sfp->state == BFA_SFP_STATE_FAILED) {
		bfa_trc(sfp, sfp->state);
		return BFA_STATUS_NO_SFP_DEV;
	}

	if (sfp->state == BFA_SFP_STATE_INSERTED) {
		bfa_trc(sfp, sfp->state);
		return BFA_STATUS_DEVBUSY;  /* sfp is reading data */
	}

	/* For eloopback, all speed is allowed */
	if (sfp->is_elb)
		return BFA_STATUS_OK;

	return bfa_sfp_speed_valid(sfp, portspeed);
}
+52 −0
Original line number Diff line number Diff line
@@ -367,6 +367,58 @@ struct bfa_ablk_s {
};
#define BFA_MEM_ABLK_DMA(__bfa)		(&((__bfa)->modules.ablk.ablk_dma))

/*
 *	SFP module specific
 */
typedef void	(*bfa_cb_sfp_t) (void *cbarg, bfa_status_t status);

struct bfa_sfp_s {
	void	*dev;
	struct bfa_ioc_s	*ioc;
	struct bfa_trc_mod_s	*trcmod;
	struct sfp_mem_s	*sfpmem;
	bfa_cb_sfp_t		cbfn;
	void			*cbarg;
	enum bfi_sfp_mem_e	memtype; /* mem access type   */
	u32			status;
	struct bfa_mbox_cmd_s	mbcmd;
	u8			*dbuf_kva; /* dma buf virtual address */
	u64			dbuf_pa;   /* dma buf physical address */
	struct bfa_ioc_notify_s	ioc_notify;
	enum bfa_defs_sfp_media_e *media;
	enum bfa_port_speed	portspeed;
	bfa_cb_sfp_t		state_query_cbfn;
	void			*state_query_cbarg;
	u8			lock;
	u8			data_valid; /* data in dbuf is valid */
	u8			state;	    /* sfp state  */
	u8			state_query_lock;
	struct bfa_mem_dma_s	sfp_dma;
	u8			is_elb;	    /* eloopback  */
};

#define BFA_SFP_MOD(__bfa)	(&(__bfa)->modules.sfp)
#define BFA_MEM_SFP_DMA(__bfa)	(&(BFA_SFP_MOD(__bfa)->sfp_dma))

u32	bfa_sfp_meminfo(void);

void	bfa_sfp_attach(struct bfa_sfp_s *sfp, struct bfa_ioc_s *ioc,
			void *dev, struct bfa_trc_mod_s *trcmod);

void	bfa_sfp_memclaim(struct bfa_sfp_s *diag, u8 *dm_kva, u64 dm_pa);
void	bfa_sfp_intr(void *bfaarg, struct bfi_mbmsg_s *msg);

bfa_status_t	bfa_sfp_show(struct bfa_sfp_s *sfp, struct sfp_mem_s *sfpmem,
			     bfa_cb_sfp_t cbfn, void *cbarg);

bfa_status_t	bfa_sfp_media(struct bfa_sfp_s *sfp,
			enum bfa_defs_sfp_media_e *media,
			bfa_cb_sfp_t cbfn, void *cbarg);

bfa_status_t	bfa_sfp_speed(struct bfa_sfp_s *sfp,
			enum bfa_port_speed portspeed,
			bfa_cb_sfp_t cbfn, void *cbarg);

#define bfa_ioc_pcifn(__ioc)		((__ioc)->pcidev.pci_func)
#define bfa_ioc_devid(__ioc)		((__ioc)->pcidev.device_id)
#define bfa_ioc_bar0(__ioc)		((__ioc)->pcidev.pci_bar_kva)
+1 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ struct bfa_modules_s {
	struct bfa_port_s	port;		/*  Physical port module     */
	struct bfa_ablk_s	ablk;		/*  ASIC block config module */
	struct bfa_cee_s	cee;		/*  CEE Module	*/
	struct bfa_sfp_s	sfp;		/*  SFP module	*/
};

/*
Loading