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

[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
......@@ -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);
}
/*
......
......@@ -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__ */
......@@ -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);
}
......@@ -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)
......
......@@ -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 */
};
/*
......
......@@ -1066,6 +1066,49 @@ bfad_iocmd_cee_reset_stats(struct bfad_s *bfad, void *cmd)
return 0;
}
int
bfad_iocmd_sfp_media(struct bfad_s *bfad, void *cmd)
{
struct bfa_bsg_sfp_media_s *iocmd = (struct bfa_bsg_sfp_media_s *)cmd;
struct bfad_hal_comp fcomp;
unsigned long flags;
init_completion(&fcomp.comp);
spin_lock_irqsave(&bfad->bfad_lock, flags);
iocmd->status = bfa_sfp_media(BFA_SFP_MOD(&bfad->bfa), &iocmd->media,
bfad_hcb_comp, &fcomp);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
bfa_trc(bfad, iocmd->status);
if (iocmd->status != BFA_STATUS_SFP_NOT_READY)
goto out;
wait_for_completion(&fcomp.comp);
iocmd->status = fcomp.status;
out:
return 0;
}
int
bfad_iocmd_sfp_speed(struct bfad_s *bfad, void *cmd)
{
struct bfa_bsg_sfp_speed_s *iocmd = (struct bfa_bsg_sfp_speed_s *)cmd;
struct bfad_hal_comp fcomp;
unsigned long flags;
init_completion(&fcomp.comp);
spin_lock_irqsave(&bfad->bfad_lock, flags);
iocmd->status = bfa_sfp_speed(BFA_SFP_MOD(&bfad->bfa), iocmd->speed,
bfad_hcb_comp, &fcomp);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
bfa_trc(bfad, iocmd->status);
if (iocmd->status != BFA_STATUS_SFP_NOT_READY)
goto out;
wait_for_completion(&fcomp.comp);
iocmd->status = fcomp.status;
out:
return 0;
}
static int
bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd,
unsigned int payload_len)
......@@ -1194,6 +1237,12 @@ bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd,
case IOCMD_CEE_RESET_STATS:
rc = bfad_iocmd_cee_reset_stats(bfad, iocmd);
break;
case IOCMD_SFP_MEDIA:
rc = bfad_iocmd_sfp_media(bfad, iocmd);
break;
case IOCMD_SFP_SPEED:
rc = bfad_iocmd_sfp_speed(bfad, iocmd);
break;
default:
rc = EINVAL;
break;
......
......@@ -65,6 +65,8 @@ enum {
IOCMD_CEE_GET_ATTR,
IOCMD_CEE_GET_STATS,
IOCMD_CEE_RESET_STATS,
IOCMD_SFP_MEDIA,
IOCMD_SFP_SPEED,
};
struct bfa_bsg_gen_s {
......@@ -320,6 +322,20 @@ struct bfa_bsg_cee_stats_s {
u64 buf_ptr;
};
struct bfa_bsg_sfp_media_s {
bfa_status_t status;
u16 bfad_num;
u16 rsvd;
enum bfa_defs_sfp_media_e media;
};
struct bfa_bsg_sfp_speed_s {
bfa_status_t status;
u16 bfad_num;
u16 rsvd;
enum bfa_port_speed speed;
};
struct bfa_bsg_fcpt_s {
bfa_status_t status;
u16 vf_id;
......
......@@ -206,6 +206,7 @@ enum bfi_mclass {
BFI_MC_IOIM_IOCOM = 17, /* good IO completion */
BFI_MC_TSKIM = 18, /* Initiator Task management */
BFI_MC_PORT = 21, /* Physical port */
BFI_MC_SFP = 22, /* SFP module */
BFI_MC_MAX = 32
};
......@@ -765,6 +766,54 @@ union bfi_cee_i2h_msg_u {
struct bfi_cee_stats_rsp_s stats_rsp;
};
/*
* SFP related
*/
enum bfi_sfp_h2i_e {
BFI_SFP_H2I_SHOW = 1,
BFI_SFP_H2I_SCN = 2,
};
enum bfi_sfp_i2h_e {
BFI_SFP_I2H_SHOW = BFA_I2HM(BFI_SFP_H2I_SHOW),
BFI_SFP_I2H_SCN = BFA_I2HM(BFI_SFP_H2I_SCN),
};
/*
* SFP state
*/
enum bfa_sfp_stat_e {
BFA_SFP_STATE_INIT = 0, /* SFP state is uninit */
BFA_SFP_STATE_REMOVED = 1, /* SFP is removed */
BFA_SFP_STATE_INSERTED = 2, /* SFP is inserted */
BFA_SFP_STATE_VALID = 3, /* SFP is valid */
BFA_SFP_STATE_UNSUPPORT = 4, /* SFP is unsupport */
BFA_SFP_STATE_FAILED = 5, /* SFP i2c read fail */
};
/*
* SFP memory access type
*/
enum bfi_sfp_mem_e {
BFI_SFP_MEM_ALL = 0x1, /* access all data field */
BFI_SFP_MEM_DIAGEXT = 0x2, /* access diag ext data field only */
};
struct bfi_sfp_req_s {
struct bfi_mhdr_s mh;
u8 memtype;
u8 rsvd[3];
struct bfi_alen_s alen;
};
struct bfi_sfp_rsp_s {
struct bfi_mhdr_s mh;
u8 status;
u8 state;
u8 rsvd[2];
};
#pragma pack()
#endif /* __BFI_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment