| /* |
| * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. |
| * All rights reserved |
| * www.brocade.com |
| * |
| * Linux driver for Brocade Fibre Channel Host Bus Adapter. |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License (GPL) Version 2 as |
| * published by the Free Software Foundation |
| * |
| * This program is distributed in the hope that it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * General Public License for more details. |
| */ |
| |
| #include <bfa.h> |
| #include <bfi/bfi_uf.h> |
| #include <cs/bfa_debug.h> |
| |
| BFA_TRC_FILE(HAL, FCXP); |
| BFA_MODULE(fcxp); |
| |
| /** |
| * forward declarations |
| */ |
| static void __bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete); |
| static void hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp, |
| struct bfi_fcxp_send_rsp_s *fcxp_rsp); |
| static void hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen, |
| struct bfa_fcxp_s *fcxp, struct fchs_s *fchs); |
| static void bfa_fcxp_qresume(void *cbarg); |
| static void bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, |
| struct bfi_fcxp_send_req_s *send_req); |
| |
| /** |
| * fcxp_pvt BFA FCXP private functions |
| */ |
| |
| static void |
| claim_fcxp_req_rsp_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi) |
| { |
| u8 *dm_kva = NULL; |
| u64 dm_pa; |
| u32 buf_pool_sz; |
| |
| dm_kva = bfa_meminfo_dma_virt(mi); |
| dm_pa = bfa_meminfo_dma_phys(mi); |
| |
| buf_pool_sz = mod->req_pld_sz * mod->num_fcxps; |
| |
| /* |
| * Initialize the fcxp req payload list |
| */ |
| mod->req_pld_list_kva = dm_kva; |
| mod->req_pld_list_pa = dm_pa; |
| dm_kva += buf_pool_sz; |
| dm_pa += buf_pool_sz; |
| bfa_os_memset(mod->req_pld_list_kva, 0, buf_pool_sz); |
| |
| /* |
| * Initialize the fcxp rsp payload list |
| */ |
| buf_pool_sz = mod->rsp_pld_sz * mod->num_fcxps; |
| mod->rsp_pld_list_kva = dm_kva; |
| mod->rsp_pld_list_pa = dm_pa; |
| dm_kva += buf_pool_sz; |
| dm_pa += buf_pool_sz; |
| bfa_os_memset(mod->rsp_pld_list_kva, 0, buf_pool_sz); |
| |
| bfa_meminfo_dma_virt(mi) = dm_kva; |
| bfa_meminfo_dma_phys(mi) = dm_pa; |
| } |
| |
| static void |
| claim_fcxps_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi) |
| { |
| u16 i; |
| struct bfa_fcxp_s *fcxp; |
| |
| fcxp = (struct bfa_fcxp_s *) bfa_meminfo_kva(mi); |
| bfa_os_memset(fcxp, 0, sizeof(struct bfa_fcxp_s) * mod->num_fcxps); |
| |
| INIT_LIST_HEAD(&mod->fcxp_free_q); |
| INIT_LIST_HEAD(&mod->fcxp_active_q); |
| |
| mod->fcxp_list = fcxp; |
| |
| for (i = 0; i < mod->num_fcxps; i++) { |
| fcxp->fcxp_mod = mod; |
| fcxp->fcxp_tag = i; |
| |
| list_add_tail(&fcxp->qe, &mod->fcxp_free_q); |
| bfa_reqq_winit(&fcxp->reqq_wqe, bfa_fcxp_qresume, fcxp); |
| fcxp->reqq_waiting = BFA_FALSE; |
| |
| fcxp = fcxp + 1; |
| } |
| |
| bfa_meminfo_kva(mi) = (void *)fcxp; |
| } |
| |
| static void |
| bfa_fcxp_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, |
| u32 *dm_len) |
| { |
| u16 num_fcxp_reqs = cfg->fwcfg.num_fcxp_reqs; |
| |
| if (num_fcxp_reqs == 0) |
| return; |
| |
| /* |
| * Account for req/rsp payload |
| */ |
| *dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs; |
| if (cfg->drvcfg.min_cfg) |
| *dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs; |
| else |
| *dm_len += BFA_FCXP_MAX_LBUF_SZ * num_fcxp_reqs; |
| |
| /* |
| * Account for fcxp structs |
| */ |
| *ndm_len += sizeof(struct bfa_fcxp_s) * num_fcxp_reqs; |
| } |
| |
| static void |
| bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, |
| struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) |
| { |
| struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); |
| |
| bfa_os_memset(mod, 0, sizeof(struct bfa_fcxp_mod_s)); |
| mod->bfa = bfa; |
| mod->num_fcxps = cfg->fwcfg.num_fcxp_reqs; |
| |
| /** |
| * Initialize FCXP request and response payload sizes. |
| */ |
| mod->req_pld_sz = mod->rsp_pld_sz = BFA_FCXP_MAX_IBUF_SZ; |
| if (!cfg->drvcfg.min_cfg) |
| mod->rsp_pld_sz = BFA_FCXP_MAX_LBUF_SZ; |
| |
| INIT_LIST_HEAD(&mod->wait_q); |
| |
| claim_fcxp_req_rsp_mem(mod, meminfo); |
| claim_fcxps_mem(mod, meminfo); |
| } |
| |
| static void |
| bfa_fcxp_initdone(struct bfa_s *bfa) |
| { |
| } |
| |
| static void |
| bfa_fcxp_detach(struct bfa_s *bfa) |
| { |
| } |
| |
| static void |
| bfa_fcxp_start(struct bfa_s *bfa) |
| { |
| } |
| |
| static void |
| bfa_fcxp_stop(struct bfa_s *bfa) |
| { |
| } |
| |
| static void |
| bfa_fcxp_iocdisable(struct bfa_s *bfa) |
| { |
| struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); |
| struct bfa_fcxp_s *fcxp; |
| struct list_head *qe, *qen; |
| |
| list_for_each_safe(qe, qen, &mod->fcxp_active_q) { |
| fcxp = (struct bfa_fcxp_s *) qe; |
| if (fcxp->caller == NULL) { |
| fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg, |
| BFA_STATUS_IOC_FAILURE, 0, 0, NULL); |
| bfa_fcxp_free(fcxp); |
| } else { |
| fcxp->rsp_status = BFA_STATUS_IOC_FAILURE; |
| bfa_cb_queue(bfa, &fcxp->hcb_qe, |
| __bfa_fcxp_send_cbfn, fcxp); |
| } |
| } |
| } |
| |
| static struct bfa_fcxp_s * |
| bfa_fcxp_get(struct bfa_fcxp_mod_s *fm) |
| { |
| struct bfa_fcxp_s *fcxp; |
| |
| bfa_q_deq(&fm->fcxp_free_q, &fcxp); |
| |
| if (fcxp) |
| list_add_tail(&fcxp->qe, &fm->fcxp_active_q); |
| |
| return (fcxp); |
| } |
| |
| static void |
| bfa_fcxp_put(struct bfa_fcxp_s *fcxp) |
| { |
| struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; |
| struct bfa_fcxp_wqe_s *wqe; |
| |
| bfa_q_deq(&mod->wait_q, &wqe); |
| if (wqe) { |
| bfa_trc(mod->bfa, fcxp->fcxp_tag); |
| wqe->alloc_cbfn(wqe->alloc_cbarg, fcxp); |
| return; |
| } |
| |
| bfa_assert(bfa_q_is_on_q(&mod->fcxp_active_q, fcxp)); |
| list_del(&fcxp->qe); |
| list_add_tail(&fcxp->qe, &mod->fcxp_free_q); |
| } |
| |
| static void |
| bfa_fcxp_null_comp(void *bfad_fcxp, struct bfa_fcxp_s *fcxp, void *cbarg, |
| bfa_status_t req_status, u32 rsp_len, |
| u32 resid_len, struct fchs_s *rsp_fchs) |
| { |
| /**discarded fcxp completion */ |
| } |
| |
| static void |
| __bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete) |
| { |
| struct bfa_fcxp_s *fcxp = cbarg; |
| |
| if (complete) { |
| fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg, |
| fcxp->rsp_status, fcxp->rsp_len, |
| fcxp->residue_len, &fcxp->rsp_fchs); |
| } else { |
| bfa_fcxp_free(fcxp); |
| } |
| } |
| |
| static void |
| hal_fcxp_send_comp(struct bfa_s *bfa, struct bfi_fcxp_send_rsp_s *fcxp_rsp) |
| { |
| struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); |
| struct bfa_fcxp_s *fcxp; |
| u16 fcxp_tag = bfa_os_ntohs(fcxp_rsp->fcxp_tag); |
| |
| bfa_trc(bfa, fcxp_tag); |
| |
| fcxp_rsp->rsp_len = bfa_os_ntohl(fcxp_rsp->rsp_len); |
| |
| /** |
| * @todo f/w should not set residue to non-0 when everything |
| * is received. |
| */ |
| if (fcxp_rsp->req_status == BFA_STATUS_OK) |
| fcxp_rsp->residue_len = 0; |
| else |
| fcxp_rsp->residue_len = bfa_os_ntohl(fcxp_rsp->residue_len); |
| |
| fcxp = BFA_FCXP_FROM_TAG(mod, fcxp_tag); |
| |
| bfa_assert(fcxp->send_cbfn != NULL); |
| |
| hal_fcxp_rx_plog(mod->bfa, fcxp, fcxp_rsp); |
| |
| if (fcxp->send_cbfn != NULL) { |
| if (fcxp->caller == NULL) { |
| bfa_trc(mod->bfa, fcxp->fcxp_tag); |
| |
| fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg, |
| fcxp_rsp->req_status, fcxp_rsp->rsp_len, |
| fcxp_rsp->residue_len, &fcxp_rsp->fchs); |
| /* |
| * fcxp automatically freed on return from the callback |
| */ |
| bfa_fcxp_free(fcxp); |
| } else { |
| bfa_trc(mod->bfa, fcxp->fcxp_tag); |
| fcxp->rsp_status = fcxp_rsp->req_status; |
| fcxp->rsp_len = fcxp_rsp->rsp_len; |
| fcxp->residue_len = fcxp_rsp->residue_len; |
| fcxp->rsp_fchs = fcxp_rsp->fchs; |
| |
| bfa_cb_queue(bfa, &fcxp->hcb_qe, |
| __bfa_fcxp_send_cbfn, fcxp); |
| } |
| } else { |
| bfa_trc(bfa, fcxp_tag); |
| } |
| } |
| |
| static void |
| hal_fcxp_set_local_sges(struct bfi_sge_s *sge, u32 reqlen, u64 req_pa) |
| { |
| union bfi_addr_u sga_zero = { {0} }; |
| |
| sge->sg_len = reqlen; |
| sge->flags = BFI_SGE_DATA_LAST; |
| bfa_dma_addr_set(sge[0].sga, req_pa); |
| bfa_sge_to_be(sge); |
| sge++; |
| |
| sge->sga = sga_zero; |
| sge->sg_len = reqlen; |
| sge->flags = BFI_SGE_PGDLEN; |
| bfa_sge_to_be(sge); |
| } |
| |
| static void |
| hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen, struct bfa_fcxp_s *fcxp, |
| struct fchs_s *fchs) |
| { |
| /* |
| * TODO: TX ox_id |
| */ |
| if (reqlen > 0) { |
| if (fcxp->use_ireqbuf) { |
| u32 pld_w0 = |
| *((u32 *) BFA_FCXP_REQ_PLD(fcxp)); |
| |
| bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP, |
| BFA_PL_EID_TX, |
| reqlen + sizeof(struct fchs_s), fchs, pld_w0); |
| } else { |
| bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, |
| BFA_PL_EID_TX, reqlen + sizeof(struct fchs_s), |
| fchs); |
| } |
| } else { |
| bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_TX, |
| reqlen + sizeof(struct fchs_s), fchs); |
| } |
| } |
| |
| static void |
| hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp, |
| struct bfi_fcxp_send_rsp_s *fcxp_rsp) |
| { |
| if (fcxp_rsp->rsp_len > 0) { |
| if (fcxp->use_irspbuf) { |
| u32 pld_w0 = |
| *((u32 *) BFA_FCXP_RSP_PLD(fcxp)); |
| |
| bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP, |
| BFA_PL_EID_RX, |
| (u16) fcxp_rsp->rsp_len, |
| &fcxp_rsp->fchs, pld_w0); |
| } else { |
| bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, |
| BFA_PL_EID_RX, |
| (u16) fcxp_rsp->rsp_len, |
| &fcxp_rsp->fchs); |
| } |
| } else { |
| bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_RX, |
| (u16) fcxp_rsp->rsp_len, &fcxp_rsp->fchs); |
| } |
| } |
| |
| /** |
| * Handler to resume sending fcxp when space in available in cpe queue. |
| */ |
| static void |
| bfa_fcxp_qresume(void *cbarg) |
| { |
| struct bfa_fcxp_s *fcxp = cbarg; |
| struct bfa_s *bfa = fcxp->fcxp_mod->bfa; |
| struct bfi_fcxp_send_req_s *send_req; |
| |
| fcxp->reqq_waiting = BFA_FALSE; |
| send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP); |
| bfa_fcxp_queue(fcxp, send_req); |
| } |
| |
| /** |
| * Queue fcxp send request to foimrware. |
| */ |
| static void |
| bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req) |
| { |
| struct bfa_s *bfa = fcxp->fcxp_mod->bfa; |
| struct bfa_fcxp_req_info_s *reqi = &fcxp->req_info; |
| struct bfa_fcxp_rsp_info_s *rspi = &fcxp->rsp_info; |
| struct bfa_rport_s *rport = reqi->bfa_rport; |
| |
| bfi_h2i_set(send_req->mh, BFI_MC_FCXP, BFI_FCXP_H2I_SEND_REQ, |
| bfa_lpuid(bfa)); |
| |
| send_req->fcxp_tag = bfa_os_htons(fcxp->fcxp_tag); |
| if (rport) { |
| send_req->rport_fw_hndl = rport->fw_handle; |
| send_req->max_frmsz = bfa_os_htons(rport->rport_info.max_frmsz); |
| if (send_req->max_frmsz == 0) |
| send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ); |
| } else { |
| send_req->rport_fw_hndl = 0; |
| send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ); |
| } |
| |
| send_req->vf_id = bfa_os_htons(reqi->vf_id); |
| send_req->lp_tag = reqi->lp_tag; |
| send_req->class = reqi->class; |
| send_req->rsp_timeout = rspi->rsp_timeout; |
| send_req->cts = reqi->cts; |
| send_req->fchs = reqi->fchs; |
| |
| send_req->req_len = bfa_os_htonl(reqi->req_tot_len); |
| send_req->rsp_maxlen = bfa_os_htonl(rspi->rsp_maxlen); |
| |
| /* |
| * setup req sgles |
| */ |
| if (fcxp->use_ireqbuf == 1) { |
| hal_fcxp_set_local_sges(send_req->req_sge, reqi->req_tot_len, |
| BFA_FCXP_REQ_PLD_PA(fcxp)); |
| } else { |
| if (fcxp->nreq_sgles > 0) { |
| bfa_assert(fcxp->nreq_sgles == 1); |
| hal_fcxp_set_local_sges(send_req->req_sge, |
| reqi->req_tot_len, |
| fcxp->req_sga_cbfn(fcxp->caller, |
| 0)); |
| } else { |
| bfa_assert(reqi->req_tot_len == 0); |
| hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0); |
| } |
| } |
| |
| /* |
| * setup rsp sgles |
| */ |
| if (fcxp->use_irspbuf == 1) { |
| bfa_assert(rspi->rsp_maxlen <= BFA_FCXP_MAX_LBUF_SZ); |
| |
| hal_fcxp_set_local_sges(send_req->rsp_sge, rspi->rsp_maxlen, |
| BFA_FCXP_RSP_PLD_PA(fcxp)); |
| |
| } else { |
| if (fcxp->nrsp_sgles > 0) { |
| bfa_assert(fcxp->nrsp_sgles == 1); |
| hal_fcxp_set_local_sges(send_req->rsp_sge, |
| rspi->rsp_maxlen, |
| fcxp->rsp_sga_cbfn(fcxp->caller, |
| 0)); |
| } else { |
| bfa_assert(rspi->rsp_maxlen == 0); |
| hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0); |
| } |
| } |
| |
| hal_fcxp_tx_plog(bfa, reqi->req_tot_len, fcxp, &reqi->fchs); |
| |
| bfa_reqq_produce(bfa, BFA_REQQ_FCXP); |
| |
| bfa_trc(bfa, bfa_reqq_pi(bfa, BFA_REQQ_FCXP)); |
| bfa_trc(bfa, bfa_reqq_ci(bfa, BFA_REQQ_FCXP)); |
| } |
| |
| |
| /** |
| * hal_fcxp_api BFA FCXP API |
| */ |
| |
| /** |
| * Allocate an FCXP instance to send a response or to send a request |
| * that has a response. Request/response buffers are allocated by caller. |
| * |
| * @param[in] bfa BFA bfa instance |
| * @param[in] nreq_sgles Number of SG elements required for request |
| * buffer. 0, if fcxp internal buffers are used. |
| * Use bfa_fcxp_get_reqbuf() to get the |
| * internal req buffer. |
| * @param[in] req_sgles SG elements describing request buffer. Will be |
| * copied in by BFA and hence can be freed on |
| * return from this function. |
| * @param[in] get_req_sga function ptr to be called to get a request SG |
| * Address (given the sge index). |
| * @param[in] get_req_sglen function ptr to be called to get a request SG |
| * len (given the sge index). |
| * @param[in] get_rsp_sga function ptr to be called to get a response SG |
| * Address (given the sge index). |
| * @param[in] get_rsp_sglen function ptr to be called to get a response SG |
| * len (given the sge index). |
| * |
| * @return FCXP instance. NULL on failure. |
| */ |
| struct bfa_fcxp_s * |
| bfa_fcxp_alloc(void *caller, struct bfa_s *bfa, int nreq_sgles, |
| int nrsp_sgles, bfa_fcxp_get_sgaddr_t req_sga_cbfn, |
| bfa_fcxp_get_sglen_t req_sglen_cbfn, |
| bfa_fcxp_get_sgaddr_t rsp_sga_cbfn, |
| bfa_fcxp_get_sglen_t rsp_sglen_cbfn) |
| { |
| struct bfa_fcxp_s *fcxp = NULL; |
| u32 nreq_sgpg, nrsp_sgpg; |
| |
| bfa_assert(bfa != NULL); |
| |
| fcxp = bfa_fcxp_get(BFA_FCXP_MOD(bfa)); |
| if (fcxp == NULL) |
| return (NULL); |
| |
| bfa_trc(bfa, fcxp->fcxp_tag); |
| |
| fcxp->caller = caller; |
| |
| if (nreq_sgles == 0) { |
| fcxp->use_ireqbuf = 1; |
| } else { |
| bfa_assert(req_sga_cbfn != NULL); |
| bfa_assert(req_sglen_cbfn != NULL); |
| |
| fcxp->use_ireqbuf = 0; |
| fcxp->req_sga_cbfn = req_sga_cbfn; |
| fcxp->req_sglen_cbfn = req_sglen_cbfn; |
| |
| fcxp->nreq_sgles = nreq_sgles; |
| |
| /* |
| * alloc required sgpgs |
| */ |
| if (nreq_sgles > BFI_SGE_INLINE) { |
| nreq_sgpg = BFA_SGPG_NPAGE(nreq_sgles); |
| |
| if (bfa_sgpg_malloc |
| (bfa, &fcxp->req_sgpg_q, nreq_sgpg) |
| != BFA_STATUS_OK) { |
| /* bfa_sgpg_wait(bfa, &fcxp->req_sgpg_wqe, |
| nreq_sgpg); */ |
| /* |
| * TODO |
| */ |
| } |
| } |
| } |
| |
| if (nrsp_sgles == 0) { |
| fcxp->use_irspbuf = 1; |
| } else { |
| bfa_assert(rsp_sga_cbfn != NULL); |
| bfa_assert(rsp_sglen_cbfn != NULL); |
| |
| fcxp->use_irspbuf = 0; |
| fcxp->rsp_sga_cbfn = rsp_sga_cbfn; |
| fcxp->rsp_sglen_cbfn = rsp_sglen_cbfn; |
| |
| fcxp->nrsp_sgles = nrsp_sgles; |
| /* |
| * alloc required sgpgs |
| */ |
| if (nrsp_sgles > BFI_SGE_INLINE) { |
| nrsp_sgpg = BFA_SGPG_NPAGE(nreq_sgles); |
| |
| if (bfa_sgpg_malloc |
| (bfa, &fcxp->rsp_sgpg_q, nrsp_sgpg) |
| != BFA_STATUS_OK) { |
| /* bfa_sgpg_wait(bfa, &fcxp->rsp_sgpg_wqe, |
| nrsp_sgpg); */ |
| /* |
| * TODO |
| */ |
| } |
| } |
| } |
| |
| return (fcxp); |
| } |
| |
| /** |
| * Get the internal request buffer pointer |
| * |
| * @param[in] fcxp BFA fcxp pointer |
| * |
| * @return pointer to the internal request buffer |
| */ |
| void * |
| bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp) |
| { |
| struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; |
| void *reqbuf; |
| |
| bfa_assert(fcxp->use_ireqbuf == 1); |
| reqbuf = ((u8 *)mod->req_pld_list_kva) + |
| fcxp->fcxp_tag * mod->req_pld_sz; |
| return reqbuf; |
| } |
| |
| u32 |
| bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp) |
| { |
| struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; |
| |
| return mod->req_pld_sz; |
| } |
| |
| /** |
| * Get the internal response buffer pointer |
| * |
| * @param[in] fcxp BFA fcxp pointer |
| * |
| * @return pointer to the internal request buffer |
| */ |
| void * |
| bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp) |
| { |
| struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; |
| void *rspbuf; |
| |
| bfa_assert(fcxp->use_irspbuf == 1); |
| |
| rspbuf = ((u8 *)mod->rsp_pld_list_kva) + |
| fcxp->fcxp_tag * mod->rsp_pld_sz; |
| return rspbuf; |
| } |
| |
| /** |
| * Free the BFA FCXP |
| * |
| * @param[in] fcxp BFA fcxp pointer |
| * |
| * @return void |
| */ |
| void |
| bfa_fcxp_free(struct bfa_fcxp_s *fcxp) |
| { |
| struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; |
| |
| bfa_assert(fcxp != NULL); |
| bfa_trc(mod->bfa, fcxp->fcxp_tag); |
| bfa_fcxp_put(fcxp); |
| } |
| |
| /** |
| * Send a FCXP request |
| * |
| * @param[in] fcxp BFA fcxp pointer |
| * @param[in] rport BFA rport pointer. Could be left NULL for WKA rports |
| * @param[in] vf_id virtual Fabric ID |
| * @param[in] lp_tag lport tag |
| * @param[in] cts use Continous sequence |
| * @param[in] cos fc Class of Service |
| * @param[in] reqlen request length, does not include FCHS length |
| * @param[in] fchs fc Header Pointer. The header content will be copied |
| * in by BFA. |
| * |
| * @param[in] cbfn call back function to be called on receiving |
| * the response |
| * @param[in] cbarg arg for cbfn |
| * @param[in] rsp_timeout |
| * response timeout |
| * |
| * @return bfa_status_t |
| */ |
| void |
| bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport, |
| u16 vf_id, u8 lp_tag, bfa_boolean_t cts, enum fc_cos cos, |
| u32 reqlen, struct fchs_s *fchs, bfa_cb_fcxp_send_t cbfn, |
| void *cbarg, u32 rsp_maxlen, u8 rsp_timeout) |
| { |
| struct bfa_s *bfa = fcxp->fcxp_mod->bfa; |
| struct bfa_fcxp_req_info_s *reqi = &fcxp->req_info; |
| struct bfa_fcxp_rsp_info_s *rspi = &fcxp->rsp_info; |
| struct bfi_fcxp_send_req_s *send_req; |
| |
| bfa_trc(bfa, fcxp->fcxp_tag); |
| |
| /** |
| * setup request/response info |
| */ |
| reqi->bfa_rport = rport; |
| reqi->vf_id = vf_id; |
| reqi->lp_tag = lp_tag; |
| reqi->class = cos; |
| rspi->rsp_timeout = rsp_timeout; |
| reqi->cts = cts; |
| reqi->fchs = *fchs; |
| reqi->req_tot_len = reqlen; |
| rspi->rsp_maxlen = rsp_maxlen; |
| fcxp->send_cbfn = cbfn ? cbfn : bfa_fcxp_null_comp; |
| fcxp->send_cbarg = cbarg; |
| |
| /** |
| * If no room in CPE queue, wait for |
| */ |
| send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP); |
| if (!send_req) { |
| bfa_trc(bfa, fcxp->fcxp_tag); |
| fcxp->reqq_waiting = BFA_TRUE; |
| bfa_reqq_wait(bfa, BFA_REQQ_FCXP, &fcxp->reqq_wqe); |
| return; |
| } |
| |
| bfa_fcxp_queue(fcxp, send_req); |
| } |
| |
| /** |
| * Abort a BFA FCXP |
| * |
| * @param[in] fcxp BFA fcxp pointer |
| * |
| * @return void |
| */ |
| bfa_status_t |
| bfa_fcxp_abort(struct bfa_fcxp_s *fcxp) |
| { |
| bfa_assert(0); |
| return (BFA_STATUS_OK); |
| } |
| |
| void |
| bfa_fcxp_alloc_wait(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe, |
| bfa_fcxp_alloc_cbfn_t alloc_cbfn, void *alloc_cbarg) |
| { |
| struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); |
| |
| bfa_assert(list_empty(&mod->fcxp_free_q)); |
| |
| wqe->alloc_cbfn = alloc_cbfn; |
| wqe->alloc_cbarg = alloc_cbarg; |
| list_add_tail(&wqe->qe, &mod->wait_q); |
| } |
| |
| void |
| bfa_fcxp_walloc_cancel(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe) |
| { |
| struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); |
| |
| bfa_assert(bfa_q_is_on_q(&mod->wait_q, wqe)); |
| list_del(&wqe->qe); |
| } |
| |
| void |
| bfa_fcxp_discard(struct bfa_fcxp_s *fcxp) |
| { |
| /** |
| * If waiting for room in request queue, cancel reqq wait |
| * and free fcxp. |
| */ |
| if (fcxp->reqq_waiting) { |
| fcxp->reqq_waiting = BFA_FALSE; |
| bfa_reqq_wcancel(&fcxp->reqq_wqe); |
| bfa_fcxp_free(fcxp); |
| return; |
| } |
| |
| fcxp->send_cbfn = bfa_fcxp_null_comp; |
| } |
| |
| |
| |
| /** |
| * hal_fcxp_public BFA FCXP public functions |
| */ |
| |
| void |
| bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) |
| { |
| switch (msg->mhdr.msg_id) { |
| case BFI_FCXP_I2H_SEND_RSP: |
| hal_fcxp_send_comp(bfa, (struct bfi_fcxp_send_rsp_s *) msg); |
| break; |
| |
| default: |
| bfa_trc(bfa, msg->mhdr.msg_id); |
| bfa_assert(0); |
| } |
| } |
| |
| u32 |
| bfa_fcxp_get_maxrsp(struct bfa_s *bfa) |
| { |
| struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); |
| |
| return mod->rsp_pld_sz; |
| } |
| |
| |