aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/bfa
diff options
context:
space:
mode:
authorKrishna Gudipati <kgudipat@brocade.com>2011-06-24 23:28:37 -0400
committerJames Bottomley <JBottomley@Parallels.com>2011-06-29 18:27:20 -0400
commit3350d98d6d072fc4ac3622e61dc3dc351ef01dc5 (patch)
tree44aa4df294c2bea6ff7cf84b6bbe340737fe4331 /drivers/scsi/bfa
parent3d7fc66dcd8d510aaa46ab9b914b632bc149b05c (diff)
[SCSI] bfa: Added support to query PHY.
- Added PHY sub-module. - Implemented interface to obtain stats and to read/update the fw from the PHY module. Signed-off-by: Krishna Gudipati <kgudipat@brocade.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/bfa')
-rw-r--r--drivers/scsi/bfa/bfa_core.c14
-rw-r--r--drivers/scsi/bfa/bfa_defs.h37
-rw-r--r--drivers/scsi/bfa/bfa_ioc.c521
-rw-r--r--drivers/scsi/bfa/bfa_ioc.h54
-rw-r--r--drivers/scsi/bfa/bfa_modules.h1
-rw-r--r--drivers/scsi/bfa/bfa_port.c1
-rw-r--r--drivers/scsi/bfa/bfad_bsg.c116
-rw-r--r--drivers/scsi/bfa/bfad_bsg.h26
-rw-r--r--drivers/scsi/bfa/bfi.h97
9 files changed, 867 insertions, 0 deletions
diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c
index e688ff72166d..c38e589105a5 100644
--- a/drivers/scsi/bfa/bfa_core.c
+++ b/drivers/scsi/bfa/bfa_core.c
@@ -154,6 +154,16 @@ bfa_com_diag_attach(struct bfa_s *bfa)
154 bfa_diag_memclaim(diag, diag_dma->kva_curp, diag_dma->dma_curp); 154 bfa_diag_memclaim(diag, diag_dma->kva_curp, diag_dma->dma_curp);
155} 155}
156 156
157static void
158bfa_com_phy_attach(struct bfa_s *bfa, bfa_boolean_t mincfg)
159{
160 struct bfa_phy_s *phy = BFA_PHY(bfa);
161 struct bfa_mem_dma_s *phy_dma = BFA_MEM_PHY_DMA(bfa);
162
163 bfa_phy_attach(phy, &bfa->ioc, bfa, bfa->trcmod, mincfg);
164 bfa_phy_memclaim(phy, phy_dma->kva_curp, phy_dma->dma_curp, mincfg);
165}
166
157/* 167/*
158 * BFA IOC FC related definitions 168 * BFA IOC FC related definitions
159 */ 169 */
@@ -1395,6 +1405,7 @@ bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo,
1395 struct bfa_mem_dma_s *sfp_dma = BFA_MEM_SFP_DMA(bfa); 1405 struct bfa_mem_dma_s *sfp_dma = BFA_MEM_SFP_DMA(bfa);
1396 struct bfa_mem_dma_s *flash_dma = BFA_MEM_FLASH_DMA(bfa); 1406 struct bfa_mem_dma_s *flash_dma = BFA_MEM_FLASH_DMA(bfa);
1397 struct bfa_mem_dma_s *diag_dma = BFA_MEM_DIAG_DMA(bfa); 1407 struct bfa_mem_dma_s *diag_dma = BFA_MEM_DIAG_DMA(bfa);
1408 struct bfa_mem_dma_s *phy_dma = BFA_MEM_PHY_DMA(bfa);
1398 1409
1399 WARN_ON((cfg == NULL) || (meminfo == NULL)); 1410 WARN_ON((cfg == NULL) || (meminfo == NULL));
1400 1411
@@ -1417,6 +1428,8 @@ bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo,
1417 bfa_mem_dma_setup(meminfo, flash_dma, 1428 bfa_mem_dma_setup(meminfo, flash_dma,
1418 bfa_flash_meminfo(cfg->drvcfg.min_cfg)); 1429 bfa_flash_meminfo(cfg->drvcfg.min_cfg));
1419 bfa_mem_dma_setup(meminfo, diag_dma, bfa_diag_meminfo()); 1430 bfa_mem_dma_setup(meminfo, diag_dma, bfa_diag_meminfo());
1431 bfa_mem_dma_setup(meminfo, phy_dma,
1432 bfa_phy_meminfo(cfg->drvcfg.min_cfg));
1420} 1433}
1421 1434
1422/* 1435/*
@@ -1488,6 +1501,7 @@ bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
1488 bfa_com_sfp_attach(bfa); 1501 bfa_com_sfp_attach(bfa);
1489 bfa_com_flash_attach(bfa, cfg->drvcfg.min_cfg); 1502 bfa_com_flash_attach(bfa, cfg->drvcfg.min_cfg);
1490 bfa_com_diag_attach(bfa); 1503 bfa_com_diag_attach(bfa);
1504 bfa_com_phy_attach(bfa, cfg->drvcfg.min_cfg);
1491} 1505}
1492 1506
1493/* 1507/*
diff --git a/drivers/scsi/bfa/bfa_defs.h b/drivers/scsi/bfa/bfa_defs.h
index ddf13d74e4b0..ed8d31b0188b 100644
--- a/drivers/scsi/bfa/bfa_defs.h
+++ b/drivers/scsi/bfa/bfa_defs.h
@@ -170,6 +170,7 @@ enum bfa_status {
170 BFA_STATUS_TRUNK_DISABLED = 165, /* Trunking is disabled on 170 BFA_STATUS_TRUNK_DISABLED = 165, /* Trunking is disabled on
171 * the adapter */ 171 * the adapter */
172 BFA_STATUS_IOPROFILE_OFF = 175, /* IO profile OFF */ 172 BFA_STATUS_IOPROFILE_OFF = 175, /* IO profile OFF */
173 BFA_STATUS_PHY_NOT_PRESENT = 183, /* PHY module not present */
173 BFA_STATUS_FEATURE_NOT_SUPPORTED = 192, /* Feature not supported */ 174 BFA_STATUS_FEATURE_NOT_SUPPORTED = 192, /* Feature not supported */
174 BFA_STATUS_FAA_ENABLED = 197, /* FAA is already enabled */ 175 BFA_STATUS_FAA_ENABLED = 197, /* FAA is already enabled */
175 BFA_STATUS_FAA_DISABLED = 198, /* FAA is already disabled */ 176 BFA_STATUS_FAA_DISABLED = 198, /* FAA is already disabled */
@@ -939,6 +940,42 @@ struct bfa_diag_loopback_s {
939 u8 rsvd[2]; 940 u8 rsvd[2];
940}; 941};
941 942
943/*
944 * PHY module specific
945 */
946enum bfa_phy_status_e {
947 BFA_PHY_STATUS_GOOD = 0, /* phy is good */
948 BFA_PHY_STATUS_NOT_PRESENT = 1, /* phy does not exist */
949 BFA_PHY_STATUS_BAD = 2, /* phy is bad */
950};
951
952/*
953 * phy attributes for phy query
954 */
955struct bfa_phy_attr_s {
956 u32 status; /* phy present/absent status */
957 u32 length; /* firmware length */
958 u32 fw_ver; /* firmware version */
959 u32 an_status; /* AN status */
960 u32 pma_pmd_status; /* PMA/PMD link status */
961 u32 pma_pmd_signal; /* PMA/PMD signal detect */
962 u32 pcs_status; /* PCS link status */
963};
964
965/*
966 * phy stats
967 */
968struct bfa_phy_stats_s {
969 u32 status; /* phy stats status */
970 u32 link_breaks; /* Num of link breaks after linkup */
971 u32 pma_pmd_fault; /* NPMA/PMD fault */
972 u32 pcs_fault; /* PCS fault */
973 u32 speed_neg; /* Num of speed negotiation */
974 u32 tx_eq_training; /* Num of TX EQ training */
975 u32 tx_eq_timeout; /* Num of TX EQ timeout */
976 u32 crc_error; /* Num of CRC errors */
977};
978
942#pragma pack() 979#pragma pack()
943 980
944#endif /* __BFA_DEFS_H__ */ 981#endif /* __BFA_DEFS_H__ */
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c
index 31467780b619..d6c2bf3865d2 100644
--- a/drivers/scsi/bfa/bfa_ioc.c
+++ b/drivers/scsi/bfa/bfa_ioc.c
@@ -2159,6 +2159,7 @@ void
2159bfa_ioc_detach(struct bfa_ioc_s *ioc) 2159bfa_ioc_detach(struct bfa_ioc_s *ioc)
2160{ 2160{
2161 bfa_fsm_send_event(ioc, IOC_E_DETACH); 2161 bfa_fsm_send_event(ioc, IOC_E_DETACH);
2162 INIT_LIST_HEAD(&ioc->notify_q);
2162} 2163}
2163 2164
2164/* 2165/*
@@ -3120,6 +3121,7 @@ bfa_ablk_attach(struct bfa_ablk_s *ablk, struct bfa_ioc_s *ioc)
3120 ablk->ioc = ioc; 3121 ablk->ioc = ioc;
3121 3122
3122 bfa_ioc_mbox_regisr(ablk->ioc, BFI_MC_ABLK, bfa_ablk_isr, ablk); 3123 bfa_ioc_mbox_regisr(ablk->ioc, BFI_MC_ABLK, bfa_ablk_isr, ablk);
3124 bfa_q_qe_init(&ablk->ioc_notify);
3123 bfa_ioc_notify_init(&ablk->ioc_notify, bfa_ablk_notify, ablk); 3125 bfa_ioc_notify_init(&ablk->ioc_notify, bfa_ablk_notify, ablk);
3124 list_add_tail(&ablk->ioc_notify.qe, &ablk->ioc->notify_q); 3126 list_add_tail(&ablk->ioc_notify.qe, &ablk->ioc->notify_q);
3125} 3127}
@@ -4895,3 +4897,522 @@ bfa_diag_memclaim(struct bfa_diag_s *diag, u8 *dm_kva, u64 dm_pa)
4895 diag->fwping.dbuf_pa = dm_pa; 4897 diag->fwping.dbuf_pa = dm_pa;
4896 memset(diag->fwping.dbuf_kva, 0, BFI_DIAG_DMA_BUF_SZ); 4898 memset(diag->fwping.dbuf_kva, 0, BFI_DIAG_DMA_BUF_SZ);
4897} 4899}
4900
4901/*
4902 * PHY module specific
4903 */
4904#define BFA_PHY_DMA_BUF_SZ 0x02000 /* 8k dma buffer */
4905#define BFA_PHY_LOCK_STATUS 0x018878 /* phy semaphore status reg */
4906
4907static void
4908bfa_phy_ntoh32(u32 *obuf, u32 *ibuf, int sz)
4909{
4910 int i, m = sz >> 2;
4911
4912 for (i = 0; i < m; i++)
4913 obuf[i] = be32_to_cpu(ibuf[i]);
4914}
4915
4916static bfa_boolean_t
4917bfa_phy_present(struct bfa_phy_s *phy)
4918{
4919 return (phy->ioc->attr->card_type == BFA_MFG_TYPE_LIGHTNING);
4920}
4921
4922static void
4923bfa_phy_notify(void *cbarg, enum bfa_ioc_event_e event)
4924{
4925 struct bfa_phy_s *phy = cbarg;
4926
4927 bfa_trc(phy, event);
4928
4929 switch (event) {
4930 case BFA_IOC_E_DISABLED:
4931 case BFA_IOC_E_FAILED:
4932 if (phy->op_busy) {
4933 phy->status = BFA_STATUS_IOC_FAILURE;
4934 phy->cbfn(phy->cbarg, phy->status);
4935 phy->op_busy = 0;
4936 }
4937 break;
4938
4939 default:
4940 break;
4941 }
4942}
4943
4944/*
4945 * Send phy attribute query request.
4946 *
4947 * @param[in] cbarg - callback argument
4948 */
4949static void
4950bfa_phy_query_send(void *cbarg)
4951{
4952 struct bfa_phy_s *phy = cbarg;
4953 struct bfi_phy_query_req_s *msg =
4954 (struct bfi_phy_query_req_s *) phy->mb.msg;
4955
4956 msg->instance = phy->instance;
4957 bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_QUERY_REQ,
4958 bfa_ioc_portid(phy->ioc));
4959 bfa_alen_set(&msg->alen, sizeof(struct bfa_phy_attr_s), phy->dbuf_pa);
4960 bfa_ioc_mbox_queue(phy->ioc, &phy->mb);
4961}
4962
4963/*
4964 * Send phy write request.
4965 *
4966 * @param[in] cbarg - callback argument
4967 */
4968static void
4969bfa_phy_write_send(void *cbarg)
4970{
4971 struct bfa_phy_s *phy = cbarg;
4972 struct bfi_phy_write_req_s *msg =
4973 (struct bfi_phy_write_req_s *) phy->mb.msg;
4974 u32 len;
4975 u16 *buf, *dbuf;
4976 int i, sz;
4977
4978 msg->instance = phy->instance;
4979 msg->offset = cpu_to_be32(phy->addr_off + phy->offset);
4980 len = (phy->residue < BFA_PHY_DMA_BUF_SZ) ?
4981 phy->residue : BFA_PHY_DMA_BUF_SZ;
4982 msg->length = cpu_to_be32(len);
4983
4984 /* indicate if it's the last msg of the whole write operation */
4985 msg->last = (len == phy->residue) ? 1 : 0;
4986
4987 bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_WRITE_REQ,
4988 bfa_ioc_portid(phy->ioc));
4989 bfa_alen_set(&msg->alen, len, phy->dbuf_pa);
4990
4991 buf = (u16 *) (phy->ubuf + phy->offset);
4992 dbuf = (u16 *)phy->dbuf_kva;
4993 sz = len >> 1;
4994 for (i = 0; i < sz; i++)
4995 buf[i] = cpu_to_be16(dbuf[i]);
4996
4997 bfa_ioc_mbox_queue(phy->ioc, &phy->mb);
4998
4999 phy->residue -= len;
5000 phy->offset += len;
5001}
5002
5003/*
5004 * Send phy read request.
5005 *
5006 * @param[in] cbarg - callback argument
5007 */
5008static void
5009bfa_phy_read_send(void *cbarg)
5010{
5011 struct bfa_phy_s *phy = cbarg;
5012 struct bfi_phy_read_req_s *msg =
5013 (struct bfi_phy_read_req_s *) phy->mb.msg;
5014 u32 len;
5015
5016 msg->instance = phy->instance;
5017 msg->offset = cpu_to_be32(phy->addr_off + phy->offset);
5018 len = (phy->residue < BFA_PHY_DMA_BUF_SZ) ?
5019 phy->residue : BFA_PHY_DMA_BUF_SZ;
5020 msg->length = cpu_to_be32(len);
5021 bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_READ_REQ,
5022 bfa_ioc_portid(phy->ioc));
5023 bfa_alen_set(&msg->alen, len, phy->dbuf_pa);
5024 bfa_ioc_mbox_queue(phy->ioc, &phy->mb);
5025}
5026
5027/*
5028 * Send phy stats request.
5029 *
5030 * @param[in] cbarg - callback argument
5031 */
5032static void
5033bfa_phy_stats_send(void *cbarg)
5034{
5035 struct bfa_phy_s *phy = cbarg;
5036 struct bfi_phy_stats_req_s *msg =
5037 (struct bfi_phy_stats_req_s *) phy->mb.msg;
5038
5039 msg->instance = phy->instance;
5040 bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_STATS_REQ,
5041 bfa_ioc_portid(phy->ioc));
5042 bfa_alen_set(&msg->alen, sizeof(struct bfa_phy_stats_s), phy->dbuf_pa);
5043 bfa_ioc_mbox_queue(phy->ioc, &phy->mb);
5044}
5045
5046/*
5047 * Flash memory info API.
5048 *
5049 * @param[in] mincfg - minimal cfg variable
5050 */
5051u32
5052bfa_phy_meminfo(bfa_boolean_t mincfg)
5053{
5054 /* min driver doesn't need phy */
5055 if (mincfg)
5056 return 0;
5057
5058 return BFA_ROUNDUP(BFA_PHY_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);
5059}
5060
5061/*
5062 * Flash attach API.
5063 *
5064 * @param[in] phy - phy structure
5065 * @param[in] ioc - ioc structure
5066 * @param[in] dev - device structure
5067 * @param[in] trcmod - trace module
5068 * @param[in] logmod - log module
5069 */
5070void
5071bfa_phy_attach(struct bfa_phy_s *phy, struct bfa_ioc_s *ioc, void *dev,
5072 struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg)
5073{
5074 phy->ioc = ioc;
5075 phy->trcmod = trcmod;
5076 phy->cbfn = NULL;
5077 phy->cbarg = NULL;
5078 phy->op_busy = 0;
5079
5080 bfa_ioc_mbox_regisr(phy->ioc, BFI_MC_PHY, bfa_phy_intr, phy);
5081 bfa_q_qe_init(&phy->ioc_notify);
5082 bfa_ioc_notify_init(&phy->ioc_notify, bfa_phy_notify, phy);
5083 list_add_tail(&phy->ioc_notify.qe, &phy->ioc->notify_q);
5084
5085 /* min driver doesn't need phy */
5086 if (mincfg) {
5087 phy->dbuf_kva = NULL;
5088 phy->dbuf_pa = 0;
5089 }
5090}
5091
5092/*
5093 * Claim memory for phy
5094 *
5095 * @param[in] phy - phy structure
5096 * @param[in] dm_kva - pointer to virtual memory address
5097 * @param[in] dm_pa - physical memory address
5098 * @param[in] mincfg - minimal cfg variable
5099 */
5100void
5101bfa_phy_memclaim(struct bfa_phy_s *phy, u8 *dm_kva, u64 dm_pa,
5102 bfa_boolean_t mincfg)
5103{
5104 if (mincfg)
5105 return;
5106
5107 phy->dbuf_kva = dm_kva;
5108 phy->dbuf_pa = dm_pa;
5109 memset(phy->dbuf_kva, 0, BFA_PHY_DMA_BUF_SZ);
5110 dm_kva += BFA_ROUNDUP(BFA_PHY_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);
5111 dm_pa += BFA_ROUNDUP(BFA_PHY_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);
5112}
5113
5114bfa_boolean_t
5115bfa_phy_busy(struct bfa_ioc_s *ioc)
5116{
5117 void __iomem *rb;
5118
5119 rb = bfa_ioc_bar0(ioc);
5120 return readl(rb + BFA_PHY_LOCK_STATUS);
5121}
5122
5123/*
5124 * Get phy attribute.
5125 *
5126 * @param[in] phy - phy structure
5127 * @param[in] attr - phy attribute structure
5128 * @param[in] cbfn - callback function
5129 * @param[in] cbarg - callback argument
5130 *
5131 * Return status.
5132 */
5133bfa_status_t
5134bfa_phy_get_attr(struct bfa_phy_s *phy, u8 instance,
5135 struct bfa_phy_attr_s *attr, bfa_cb_phy_t cbfn, void *cbarg)
5136{
5137 bfa_trc(phy, BFI_PHY_H2I_QUERY_REQ);
5138 bfa_trc(phy, instance);
5139
5140 if (!bfa_phy_present(phy))
5141 return BFA_STATUS_PHY_NOT_PRESENT;
5142
5143 if (!bfa_ioc_is_operational(phy->ioc))
5144 return BFA_STATUS_IOC_NON_OP;
5145
5146 if (phy->op_busy || bfa_phy_busy(phy->ioc)) {
5147 bfa_trc(phy, phy->op_busy);
5148 return BFA_STATUS_DEVBUSY;
5149 }
5150
5151 phy->op_busy = 1;
5152 phy->cbfn = cbfn;
5153 phy->cbarg = cbarg;
5154 phy->instance = instance;
5155 phy->ubuf = (uint8_t *) attr;
5156 bfa_phy_query_send(phy);
5157
5158 return BFA_STATUS_OK;
5159}
5160
5161/*
5162 * Get phy stats.
5163 *
5164 * @param[in] phy - phy structure
5165 * @param[in] instance - phy image instance
5166 * @param[in] stats - pointer to phy stats
5167 * @param[in] cbfn - callback function
5168 * @param[in] cbarg - callback argument
5169 *
5170 * Return status.
5171 */
5172bfa_status_t
5173bfa_phy_get_stats(struct bfa_phy_s *phy, u8 instance,
5174 struct bfa_phy_stats_s *stats,
5175 bfa_cb_phy_t cbfn, void *cbarg)
5176{
5177 bfa_trc(phy, BFI_PHY_H2I_STATS_REQ);
5178 bfa_trc(phy, instance);
5179
5180 if (!bfa_phy_present(phy))
5181 return BFA_STATUS_PHY_NOT_PRESENT;
5182
5183 if (!bfa_ioc_is_operational(phy->ioc))
5184 return BFA_STATUS_IOC_NON_OP;
5185
5186 if (phy->op_busy || bfa_phy_busy(phy->ioc)) {
5187 bfa_trc(phy, phy->op_busy);
5188 return BFA_STATUS_DEVBUSY;
5189 }
5190
5191 phy->op_busy = 1;
5192 phy->cbfn = cbfn;
5193 phy->cbarg = cbarg;
5194 phy->instance = instance;
5195 phy->ubuf = (u8 *) stats;
5196 bfa_phy_stats_send(phy);
5197
5198 return BFA_STATUS_OK;
5199}
5200
5201/*
5202 * Update phy image.
5203 *
5204 * @param[in] phy - phy structure
5205 * @param[in] instance - phy image instance
5206 * @param[in] buf - update data buffer
5207 * @param[in] len - data buffer length
5208 * @param[in] offset - offset relative to starting address
5209 * @param[in] cbfn - callback function
5210 * @param[in] cbarg - callback argument
5211 *
5212 * Return status.
5213 */
5214bfa_status_t
5215bfa_phy_update(struct bfa_phy_s *phy, u8 instance,
5216 void *buf, u32 len, u32 offset,
5217 bfa_cb_phy_t cbfn, void *cbarg)
5218{
5219 bfa_trc(phy, BFI_PHY_H2I_WRITE_REQ);
5220 bfa_trc(phy, instance);
5221 bfa_trc(phy, len);
5222 bfa_trc(phy, offset);
5223
5224 if (!bfa_phy_present(phy))
5225 return BFA_STATUS_PHY_NOT_PRESENT;
5226
5227 if (!bfa_ioc_is_operational(phy->ioc))
5228 return BFA_STATUS_IOC_NON_OP;
5229
5230 /* 'len' must be in word (4-byte) boundary */
5231 if (!len || (len & 0x03))
5232 return BFA_STATUS_FAILED;
5233
5234 if (phy->op_busy || bfa_phy_busy(phy->ioc)) {
5235 bfa_trc(phy, phy->op_busy);
5236 return BFA_STATUS_DEVBUSY;
5237 }
5238
5239 phy->op_busy = 1;
5240 phy->cbfn = cbfn;
5241 phy->cbarg = cbarg;
5242 phy->instance = instance;
5243 phy->residue = len;
5244 phy->offset = 0;
5245 phy->addr_off = offset;
5246 phy->ubuf = buf;
5247
5248 bfa_phy_write_send(phy);
5249 return BFA_STATUS_OK;
5250}
5251
5252/*
5253 * Read phy image.
5254 *
5255 * @param[in] phy - phy structure
5256 * @param[in] instance - phy image instance
5257 * @param[in] buf - read data buffer
5258 * @param[in] len - data buffer length
5259 * @param[in] offset - offset relative to starting address
5260 * @param[in] cbfn - callback function
5261 * @param[in] cbarg - callback argument
5262 *
5263 * Return status.
5264 */
5265bfa_status_t
5266bfa_phy_read(struct bfa_phy_s *phy, u8 instance,
5267 void *buf, u32 len, u32 offset,
5268 bfa_cb_phy_t cbfn, void *cbarg)
5269{
5270 bfa_trc(phy, BFI_PHY_H2I_READ_REQ);
5271 bfa_trc(phy, instance);
5272 bfa_trc(phy, len);
5273 bfa_trc(phy, offset);
5274
5275 if (!bfa_phy_present(phy))
5276 return BFA_STATUS_PHY_NOT_PRESENT;
5277
5278 if (!bfa_ioc_is_operational(phy->ioc))
5279 return BFA_STATUS_IOC_NON_OP;
5280
5281 /* 'len' must be in word (4-byte) boundary */
5282 if (!len || (len & 0x03))
5283 return BFA_STATUS_FAILED;
5284
5285 if (phy->op_busy || bfa_phy_busy(phy->ioc)) {
5286 bfa_trc(phy, phy->op_busy);
5287 return BFA_STATUS_DEVBUSY;
5288 }
5289
5290 phy->op_busy = 1;
5291 phy->cbfn = cbfn;
5292 phy->cbarg = cbarg;
5293 phy->instance = instance;
5294 phy->residue = len;
5295 phy->offset = 0;
5296 phy->addr_off = offset;
5297 phy->ubuf = buf;
5298 bfa_phy_read_send(phy);
5299
5300 return BFA_STATUS_OK;
5301}
5302
5303/*
5304 * Process phy response messages upon receiving interrupts.
5305 *
5306 * @param[in] phyarg - phy structure
5307 * @param[in] msg - message structure
5308 */
5309void
5310bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg)
5311{
5312 struct bfa_phy_s *phy = phyarg;
5313 u32 status;
5314
5315 union {
5316 struct bfi_phy_query_rsp_s *query;
5317 struct bfi_phy_stats_rsp_s *stats;
5318 struct bfi_phy_write_rsp_s *write;
5319 struct bfi_phy_read_rsp_s *read;
5320 struct bfi_mbmsg_s *msg;
5321 } m;
5322
5323 m.msg = msg;
5324 bfa_trc(phy, msg->mh.msg_id);
5325
5326 if (!phy->op_busy) {
5327 /* receiving response after ioc failure */
5328 bfa_trc(phy, 0x9999);
5329 return;
5330 }
5331
5332 switch (msg->mh.msg_id) {
5333 case BFI_PHY_I2H_QUERY_RSP:
5334 status = be32_to_cpu(m.query->status);
5335 bfa_trc(phy, status);
5336
5337 if (status == BFA_STATUS_OK) {
5338 struct bfa_phy_attr_s *attr =
5339 (struct bfa_phy_attr_s *) phy->ubuf;
5340 bfa_phy_ntoh32((u32 *)attr, (u32 *)phy->dbuf_kva,
5341 sizeof(struct bfa_phy_attr_s));
5342 bfa_trc(phy, attr->status);
5343 bfa_trc(phy, attr->length);
5344 }
5345
5346 phy->status = status;
5347 phy->op_busy = 0;
5348 if (phy->cbfn)
5349 phy->cbfn(phy->cbarg, phy->status);
5350 break;
5351 case BFI_PHY_I2H_STATS_RSP:
5352 status = be32_to_cpu(m.stats->status);
5353 bfa_trc(phy, status);
5354
5355 if (status == BFA_STATUS_OK) {
5356 struct bfa_phy_stats_s *stats =
5357 (struct bfa_phy_stats_s *) phy->ubuf;
5358 bfa_phy_ntoh32((u32 *)stats, (u32 *)phy->dbuf_kva,
5359 sizeof(struct bfa_phy_stats_s));
5360 bfa_trc(phy, stats->status);
5361 }
5362
5363 phy->status = status;
5364 phy->op_busy = 0;
5365 if (phy->cbfn)
5366 phy->cbfn(phy->cbarg, phy->status);
5367 break;
5368 case BFI_PHY_I2H_WRITE_RSP:
5369 status = be32_to_cpu(m.write->status);
5370 bfa_trc(phy, status);
5371
5372 if (status != BFA_STATUS_OK || phy->residue == 0) {
5373 phy->status = status;
5374 phy->op_busy = 0;
5375 if (phy->cbfn)
5376 phy->cbfn(phy->cbarg, phy->status);
5377 } else {
5378 bfa_trc(phy, phy->offset);
5379 bfa_phy_write_send(phy);
5380 }
5381 break;
5382 case BFI_PHY_I2H_READ_RSP:
5383 status = be32_to_cpu(m.read->status);
5384 bfa_trc(phy, status);
5385
5386 if (status != BFA_STATUS_OK) {
5387 phy->status = status;
5388 phy->op_busy = 0;
5389 if (phy->cbfn)
5390 phy->cbfn(phy->cbarg, phy->status);
5391 } else {
5392 u32 len = be32_to_cpu(m.read->length);
5393 u16 *buf = (u16 *)(phy->ubuf + phy->offset);
5394 u16 *dbuf = (u16 *)phy->dbuf_kva;
5395 int i, sz = len >> 1;
5396
5397 bfa_trc(phy, phy->offset);
5398 bfa_trc(phy, len);
5399
5400 for (i = 0; i < sz; i++)
5401 buf[i] = be16_to_cpu(dbuf[i]);
5402
5403 phy->residue -= len;
5404 phy->offset += len;
5405
5406 if (phy->residue == 0) {
5407 phy->status = status;
5408 phy->op_busy = 0;
5409 if (phy->cbfn)
5410 phy->cbfn(phy->cbarg, phy->status);
5411 } else
5412 bfa_phy_read_send(phy);
5413 }
5414 break;
5415 default:
5416 WARN_ON(1);
5417 }
5418}
diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h
index 5bcab540ea60..c5ecd2edc95d 100644
--- a/drivers/scsi/bfa/bfa_ioc.h
+++ b/drivers/scsi/bfa/bfa_ioc.h
@@ -632,6 +632,60 @@ bfa_status_t bfa_diag_beacon_port(struct bfa_diag_s *diag,
632 bfa_boolean_t beacon, bfa_boolean_t link_e2e_beacon, 632 bfa_boolean_t beacon, bfa_boolean_t link_e2e_beacon,
633 u32 sec); 633 u32 sec);
634 634
635/*
636 * PHY module specific
637 */
638typedef void (*bfa_cb_phy_t) (void *cbarg, bfa_status_t status);
639
640struct bfa_phy_s {
641 struct bfa_ioc_s *ioc; /* back pointer to ioc */
642 struct bfa_trc_mod_s *trcmod; /* trace module */
643 u8 instance; /* port instance */
644 u8 op_busy; /* operation busy flag */
645 u8 rsv[2];
646 u32 residue; /* residual length */
647 u32 offset; /* offset */
648 bfa_status_t status; /* status */
649 u8 *dbuf_kva; /* dma buf virtual address */
650 u64 dbuf_pa; /* dma buf physical address */
651 struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
652 bfa_cb_phy_t cbfn; /* user callback function */
653 void *cbarg; /* user callback arg */
654 u8 *ubuf; /* user supplied buffer */
655 struct bfa_cb_qe_s hcb_qe; /* comp: BFA callback qelem */
656 u32 addr_off; /* phy address offset */
657 struct bfa_mbox_cmd_s mb; /* mailbox */
658 struct bfa_ioc_notify_s ioc_notify; /* ioc event notify */
659 struct bfa_mem_dma_s phy_dma;
660};
661
662#define BFA_PHY(__bfa) (&(__bfa)->modules.phy)
663#define BFA_MEM_PHY_DMA(__bfa) (&(BFA_PHY(__bfa)->phy_dma))
664
665bfa_boolean_t bfa_phy_busy(struct bfa_ioc_s *ioc);
666bfa_status_t bfa_phy_get_attr(struct bfa_phy_s *phy, u8 instance,
667 struct bfa_phy_attr_s *attr,
668 bfa_cb_phy_t cbfn, void *cbarg);
669bfa_status_t bfa_phy_get_stats(struct bfa_phy_s *phy, u8 instance,
670 struct bfa_phy_stats_s *stats,
671 bfa_cb_phy_t cbfn, void *cbarg);
672bfa_status_t bfa_phy_update(struct bfa_phy_s *phy, u8 instance,
673 void *buf, u32 len, u32 offset,
674 bfa_cb_phy_t cbfn, void *cbarg);
675bfa_status_t bfa_phy_read(struct bfa_phy_s *phy, u8 instance,
676 void *buf, u32 len, u32 offset,
677 bfa_cb_phy_t cbfn, void *cbarg);
678
679u32 bfa_phy_meminfo(bfa_boolean_t mincfg);
680void bfa_phy_attach(struct bfa_phy_s *phy, struct bfa_ioc_s *ioc,
681 void *dev, struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg);
682void bfa_phy_memclaim(struct bfa_phy_s *phy,
683 u8 *dm_kva, u64 dm_pa, bfa_boolean_t mincfg);
684void bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg);
685
686/*
687 * IOC specfic macros
688 */
635#define bfa_ioc_pcifn(__ioc) ((__ioc)->pcidev.pci_func) 689#define bfa_ioc_pcifn(__ioc) ((__ioc)->pcidev.pci_func)
636#define bfa_ioc_devid(__ioc) ((__ioc)->pcidev.device_id) 690#define bfa_ioc_devid(__ioc) ((__ioc)->pcidev.device_id)
637#define bfa_ioc_bar0(__ioc) ((__ioc)->pcidev.pci_bar_kva) 691#define bfa_ioc_bar0(__ioc) ((__ioc)->pcidev.pci_bar_kva)
diff --git a/drivers/scsi/bfa/bfa_modules.h b/drivers/scsi/bfa/bfa_modules.h
index c6b2fe7ed960..1c6efd40a673 100644
--- a/drivers/scsi/bfa/bfa_modules.h
+++ b/drivers/scsi/bfa/bfa_modules.h
@@ -43,6 +43,7 @@ struct bfa_modules_s {
43 struct bfa_sfp_s sfp; /* SFP module */ 43 struct bfa_sfp_s sfp; /* SFP module */
44 struct bfa_flash_s flash; /* flash module */ 44 struct bfa_flash_s flash; /* flash module */
45 struct bfa_diag_s diag_mod; /* diagnostics module */ 45 struct bfa_diag_s diag_mod; /* diagnostics module */
46 struct bfa_phy_s phy; /* phy module */
46}; 47};
47 48
48/* 49/*
diff --git a/drivers/scsi/bfa/bfa_port.c b/drivers/scsi/bfa/bfa_port.c
index f382a475a09d..95e4ad8759ac 100644
--- a/drivers/scsi/bfa/bfa_port.c
+++ b/drivers/scsi/bfa/bfa_port.c
@@ -469,6 +469,7 @@ bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc,
469 port->pbc_disabled = BFA_FALSE; 469 port->pbc_disabled = BFA_FALSE;
470 470
471 bfa_ioc_mbox_regisr(port->ioc, BFI_MC_PORT, bfa_port_isr, port); 471 bfa_ioc_mbox_regisr(port->ioc, BFI_MC_PORT, bfa_port_isr, port);
472 bfa_q_qe_init(&port->ioc_notify);
472 bfa_ioc_notify_init(&port->ioc_notify, bfa_port_notify, port); 473 bfa_ioc_notify_init(&port->ioc_notify, bfa_port_notify, port);
473 list_add_tail(&port->ioc_notify.qe, &port->ioc->notify_q); 474 list_add_tail(&port->ioc_notify.qe, &port->ioc->notify_q);
474 475
diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c
index a60270287064..552bb250a210 100644
--- a/drivers/scsi/bfa/bfad_bsg.c
+++ b/drivers/scsi/bfa/bfad_bsg.c
@@ -1393,6 +1393,110 @@ bfad_iocmd_diag_lb_stat(struct bfad_s *bfad, void *cmd)
1393 return 0; 1393 return 0;
1394} 1394}
1395 1395
1396int
1397bfad_iocmd_phy_get_attr(struct bfad_s *bfad, void *cmd)
1398{
1399 struct bfa_bsg_phy_attr_s *iocmd =
1400 (struct bfa_bsg_phy_attr_s *)cmd;
1401 struct bfad_hal_comp fcomp;
1402 unsigned long flags;
1403
1404 init_completion(&fcomp.comp);
1405 spin_lock_irqsave(&bfad->bfad_lock, flags);
1406 iocmd->status = bfa_phy_get_attr(BFA_PHY(&bfad->bfa), iocmd->instance,
1407 &iocmd->attr, bfad_hcb_comp, &fcomp);
1408 spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1409 if (iocmd->status != BFA_STATUS_OK)
1410 goto out;
1411 wait_for_completion(&fcomp.comp);
1412 iocmd->status = fcomp.status;
1413out:
1414 return 0;
1415}
1416
1417int
1418bfad_iocmd_phy_get_stats(struct bfad_s *bfad, void *cmd)
1419{
1420 struct bfa_bsg_phy_stats_s *iocmd =
1421 (struct bfa_bsg_phy_stats_s *)cmd;
1422 struct bfad_hal_comp fcomp;
1423 unsigned long flags;
1424
1425 init_completion(&fcomp.comp);
1426 spin_lock_irqsave(&bfad->bfad_lock, flags);
1427 iocmd->status = bfa_phy_get_stats(BFA_PHY(&bfad->bfa), iocmd->instance,
1428 &iocmd->stats, bfad_hcb_comp, &fcomp);
1429 spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1430 if (iocmd->status != BFA_STATUS_OK)
1431 goto out;
1432 wait_for_completion(&fcomp.comp);
1433 iocmd->status = fcomp.status;
1434out:
1435 return 0;
1436}
1437
1438int
1439bfad_iocmd_phy_read(struct bfad_s *bfad, void *cmd, unsigned int payload_len)
1440{
1441 struct bfa_bsg_phy_s *iocmd = (struct bfa_bsg_phy_s *)cmd;
1442 struct bfad_hal_comp fcomp;
1443 void *iocmd_bufptr;
1444 unsigned long flags;
1445
1446 if (bfad_chk_iocmd_sz(payload_len,
1447 sizeof(struct bfa_bsg_phy_s),
1448 iocmd->bufsz) != BFA_STATUS_OK) {
1449 iocmd->status = BFA_STATUS_VERSION_FAIL;
1450 return 0;
1451 }
1452
1453 iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_phy_s);
1454 init_completion(&fcomp.comp);
1455 spin_lock_irqsave(&bfad->bfad_lock, flags);
1456 iocmd->status = bfa_phy_read(BFA_PHY(&bfad->bfa),
1457 iocmd->instance, iocmd_bufptr, iocmd->bufsz,
1458 0, bfad_hcb_comp, &fcomp);
1459 spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1460 if (iocmd->status != BFA_STATUS_OK)
1461 goto out;
1462 wait_for_completion(&fcomp.comp);
1463 iocmd->status = fcomp.status;
1464 if (iocmd->status != BFA_STATUS_OK)
1465 goto out;
1466out:
1467 return 0;
1468}
1469
1470int
1471bfad_iocmd_phy_update(struct bfad_s *bfad, void *cmd, unsigned int payload_len)
1472{
1473 struct bfa_bsg_phy_s *iocmd = (struct bfa_bsg_phy_s *)cmd;
1474 void *iocmd_bufptr;
1475 struct bfad_hal_comp fcomp;
1476 unsigned long flags;
1477
1478 if (bfad_chk_iocmd_sz(payload_len,
1479 sizeof(struct bfa_bsg_phy_s),
1480 iocmd->bufsz) != BFA_STATUS_OK) {
1481 iocmd->status = BFA_STATUS_VERSION_FAIL;
1482 return 0;
1483 }
1484
1485 iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_phy_s);
1486 init_completion(&fcomp.comp);
1487 spin_lock_irqsave(&bfad->bfad_lock, flags);
1488 iocmd->status = bfa_phy_update(BFA_PHY(&bfad->bfa),
1489 iocmd->instance, iocmd_bufptr, iocmd->bufsz,
1490 0, bfad_hcb_comp, &fcomp);
1491 spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1492 if (iocmd->status != BFA_STATUS_OK)
1493 goto out;
1494 wait_for_completion(&fcomp.comp);
1495 iocmd->status = fcomp.status;
1496out:
1497 return 0;
1498}
1499
1396static int 1500static int
1397bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd, 1501bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd,
1398 unsigned int payload_len) 1502 unsigned int payload_len)
@@ -1566,6 +1670,18 @@ bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd,
1566 case IOCMD_DIAG_LB_STAT: 1670 case IOCMD_DIAG_LB_STAT:
1567 rc = bfad_iocmd_diag_lb_stat(bfad, iocmd); 1671 rc = bfad_iocmd_diag_lb_stat(bfad, iocmd);
1568 break; 1672 break;
1673 case IOCMD_PHY_GET_ATTR:
1674 rc = bfad_iocmd_phy_get_attr(bfad, iocmd);
1675 break;
1676 case IOCMD_PHY_GET_STATS:
1677 rc = bfad_iocmd_phy_get_stats(bfad, iocmd);
1678 break;
1679 case IOCMD_PHY_UPDATE_FW:
1680 rc = bfad_iocmd_phy_update(bfad, iocmd, payload_len);
1681 break;
1682 case IOCMD_PHY_READ_FW:
1683 rc = bfad_iocmd_phy_read(bfad, iocmd, payload_len);
1684 break;
1569 default: 1685 default:
1570 rc = EINVAL; 1686 rc = EINVAL;
1571 break; 1687 break;
diff --git a/drivers/scsi/bfa/bfad_bsg.h b/drivers/scsi/bfa/bfad_bsg.h
index 89942773febe..5d89c1dd977a 100644
--- a/drivers/scsi/bfa/bfad_bsg.h
+++ b/drivers/scsi/bfa/bfad_bsg.h
@@ -80,6 +80,10 @@ enum {
80 IOCMD_DIAG_LED, 80 IOCMD_DIAG_LED,
81 IOCMD_DIAG_BEACON_LPORT, 81 IOCMD_DIAG_BEACON_LPORT,
82 IOCMD_DIAG_LB_STAT, 82 IOCMD_DIAG_LB_STAT,
83 IOCMD_PHY_GET_ATTR,
84 IOCMD_PHY_GET_STATS,
85 IOCMD_PHY_UPDATE_FW,
86 IOCMD_PHY_READ_FW,
83}; 87};
84 88
85struct bfa_bsg_gen_s { 89struct bfa_bsg_gen_s {
@@ -440,6 +444,28 @@ struct bfa_bsg_diag_lb_stat_s {
440 u16 rsvd; 444 u16 rsvd;
441}; 445};
442 446
447struct bfa_bsg_phy_attr_s {
448 bfa_status_t status;
449 u16 bfad_num;
450 u16 instance;
451 struct bfa_phy_attr_s attr;
452};
453
454struct bfa_bsg_phy_s {
455 bfa_status_t status;
456 u16 bfad_num;
457 u16 instance;
458 u64 bufsz;
459 u64 buf_ptr;
460};
461
462struct bfa_bsg_phy_stats_s {
463 bfa_status_t status;
464 u16 bfad_num;
465 u16 instance;
466 struct bfa_phy_stats_s stats;
467};
468
443struct bfa_bsg_fcpt_s { 469struct bfa_bsg_fcpt_s {
444 bfa_status_t status; 470 bfa_status_t status;
445 u16 vf_id; 471 u16 vf_id;
diff --git a/drivers/scsi/bfa/bfi.h b/drivers/scsi/bfa/bfi.h
index efa41b64bb32..1e258d5f8aec 100644
--- a/drivers/scsi/bfa/bfi.h
+++ b/drivers/scsi/bfa/bfi.h
@@ -209,6 +209,7 @@ enum bfi_mclass {
209 BFI_MC_TSKIM = 18, /* Initiator Task management */ 209 BFI_MC_TSKIM = 18, /* Initiator Task management */
210 BFI_MC_PORT = 21, /* Physical port */ 210 BFI_MC_PORT = 21, /* Physical port */
211 BFI_MC_SFP = 22, /* SFP module */ 211 BFI_MC_SFP = 22, /* SFP module */
212 BFI_MC_PHY = 25, /* External PHY message class */
212 BFI_MC_MAX = 32 213 BFI_MC_MAX = 32
213}; 214};
214 215
@@ -1030,6 +1031,102 @@ struct bfi_diag_qtest_req_s {
1030}; 1031};
1031#define bfi_diag_qtest_rsp_t struct bfi_diag_qtest_req_s 1032#define bfi_diag_qtest_rsp_t struct bfi_diag_qtest_req_s
1032 1033
1034/*
1035 * PHY module specific
1036 */
1037enum bfi_phy_h2i_msgs_e {
1038 BFI_PHY_H2I_QUERY_REQ = 1,
1039 BFI_PHY_H2I_STATS_REQ = 2,
1040 BFI_PHY_H2I_WRITE_REQ = 3,
1041 BFI_PHY_H2I_READ_REQ = 4,
1042};
1043
1044enum bfi_phy_i2h_msgs_e {
1045 BFI_PHY_I2H_QUERY_RSP = BFA_I2HM(1),
1046 BFI_PHY_I2H_STATS_RSP = BFA_I2HM(2),
1047 BFI_PHY_I2H_WRITE_RSP = BFA_I2HM(3),
1048 BFI_PHY_I2H_READ_RSP = BFA_I2HM(4),
1049};
1050
1051/*
1052 * External PHY query request
1053 */
1054struct bfi_phy_query_req_s {
1055 struct bfi_mhdr_s mh; /* Common msg header */
1056 u8 instance;
1057 u8 rsv[3];
1058 struct bfi_alen_s alen;
1059};
1060
1061/*
1062 * External PHY stats request
1063 */
1064struct bfi_phy_stats_req_s {
1065 struct bfi_mhdr_s mh; /* Common msg header */
1066 u8 instance;
1067 u8 rsv[3];
1068 struct bfi_alen_s alen;
1069};
1070
1071/*
1072 * External PHY write request
1073 */
1074struct bfi_phy_write_req_s {
1075 struct bfi_mhdr_s mh; /* Common msg header */
1076 u8 instance;
1077 u8 last;
1078 u8 rsv[2];
1079 u32 offset;
1080 u32 length;
1081 struct bfi_alen_s alen;
1082};
1083
1084/*
1085 * External PHY read request
1086 */
1087struct bfi_phy_read_req_s {
1088 struct bfi_mhdr_s mh; /* Common msg header */
1089 u8 instance;
1090 u8 rsv[3];
1091 u32 offset;
1092 u32 length;
1093 struct bfi_alen_s alen;
1094};
1095
1096/*
1097 * External PHY query response
1098 */
1099struct bfi_phy_query_rsp_s {
1100 struct bfi_mhdr_s mh; /* Common msg header */
1101 u32 status;
1102};
1103
1104/*
1105 * External PHY stats response
1106 */
1107struct bfi_phy_stats_rsp_s {
1108 struct bfi_mhdr_s mh; /* Common msg header */
1109 u32 status;
1110};
1111
1112/*
1113 * External PHY read response
1114 */
1115struct bfi_phy_read_rsp_s {
1116 struct bfi_mhdr_s mh; /* Common msg header */
1117 u32 status;
1118 u32 length;
1119};
1120
1121/*
1122 * External PHY write response
1123 */
1124struct bfi_phy_write_rsp_s {
1125 struct bfi_mhdr_s mh; /* Common msg header */
1126 u32 status;
1127 u32 length;
1128};
1129
1033#pragma pack() 1130#pragma pack()
1034 1131
1035#endif /* __BFI_H__ */ 1132#endif /* __BFI_H__ */