Jing Huang | 7725ccf | 2009-09-23 17:46:15 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. |
| 3 | * All rights reserved |
| 4 | * www.brocade.com |
| 5 | * |
| 6 | * Linux driver for Brocade Fibre Channel Host Bus Adapter. |
| 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify it |
| 9 | * under the terms of the GNU General Public License (GPL) Version 2 as |
| 10 | * published by the Free Software Foundation |
| 11 | * |
| 12 | * This program is distributed in the hope that it will be useful, but |
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 | * General Public License for more details. |
| 16 | */ |
| 17 | |
| 18 | #include <bfa.h> |
| 19 | #include <bfi/bfi_uf.h> |
| 20 | #include <cs/bfa_debug.h> |
| 21 | |
| 22 | BFA_TRC_FILE(HAL, FCXP); |
| 23 | BFA_MODULE(fcxp); |
| 24 | |
| 25 | /** |
| 26 | * forward declarations |
| 27 | */ |
| 28 | static void __bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete); |
| 29 | static void hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp, |
| 30 | struct bfi_fcxp_send_rsp_s *fcxp_rsp); |
| 31 | static void hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen, |
| 32 | struct bfa_fcxp_s *fcxp, struct fchs_s *fchs); |
| 33 | static void bfa_fcxp_qresume(void *cbarg); |
| 34 | static void bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, |
| 35 | struct bfi_fcxp_send_req_s *send_req); |
| 36 | |
| 37 | /** |
| 38 | * fcxp_pvt BFA FCXP private functions |
| 39 | */ |
| 40 | |
| 41 | static void |
| 42 | claim_fcxp_req_rsp_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi) |
| 43 | { |
| 44 | u8 *dm_kva = NULL; |
| 45 | u64 dm_pa; |
| 46 | u32 buf_pool_sz; |
| 47 | |
| 48 | dm_kva = bfa_meminfo_dma_virt(mi); |
| 49 | dm_pa = bfa_meminfo_dma_phys(mi); |
| 50 | |
| 51 | buf_pool_sz = mod->req_pld_sz * mod->num_fcxps; |
| 52 | |
| 53 | /* |
| 54 | * Initialize the fcxp req payload list |
| 55 | */ |
| 56 | mod->req_pld_list_kva = dm_kva; |
| 57 | mod->req_pld_list_pa = dm_pa; |
| 58 | dm_kva += buf_pool_sz; |
| 59 | dm_pa += buf_pool_sz; |
| 60 | bfa_os_memset(mod->req_pld_list_kva, 0, buf_pool_sz); |
| 61 | |
| 62 | /* |
| 63 | * Initialize the fcxp rsp payload list |
| 64 | */ |
| 65 | buf_pool_sz = mod->rsp_pld_sz * mod->num_fcxps; |
| 66 | mod->rsp_pld_list_kva = dm_kva; |
| 67 | mod->rsp_pld_list_pa = dm_pa; |
| 68 | dm_kva += buf_pool_sz; |
| 69 | dm_pa += buf_pool_sz; |
| 70 | bfa_os_memset(mod->rsp_pld_list_kva, 0, buf_pool_sz); |
| 71 | |
| 72 | bfa_meminfo_dma_virt(mi) = dm_kva; |
| 73 | bfa_meminfo_dma_phys(mi) = dm_pa; |
| 74 | } |
| 75 | |
| 76 | static void |
| 77 | claim_fcxps_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi) |
| 78 | { |
| 79 | u16 i; |
| 80 | struct bfa_fcxp_s *fcxp; |
| 81 | |
| 82 | fcxp = (struct bfa_fcxp_s *) bfa_meminfo_kva(mi); |
| 83 | bfa_os_memset(fcxp, 0, sizeof(struct bfa_fcxp_s) * mod->num_fcxps); |
| 84 | |
| 85 | INIT_LIST_HEAD(&mod->fcxp_free_q); |
| 86 | INIT_LIST_HEAD(&mod->fcxp_active_q); |
| 87 | |
| 88 | mod->fcxp_list = fcxp; |
| 89 | |
| 90 | for (i = 0; i < mod->num_fcxps; i++) { |
| 91 | fcxp->fcxp_mod = mod; |
| 92 | fcxp->fcxp_tag = i; |
| 93 | |
| 94 | list_add_tail(&fcxp->qe, &mod->fcxp_free_q); |
| 95 | bfa_reqq_winit(&fcxp->reqq_wqe, bfa_fcxp_qresume, fcxp); |
| 96 | fcxp->reqq_waiting = BFA_FALSE; |
| 97 | |
| 98 | fcxp = fcxp + 1; |
| 99 | } |
| 100 | |
| 101 | bfa_meminfo_kva(mi) = (void *)fcxp; |
| 102 | } |
| 103 | |
| 104 | static void |
| 105 | bfa_fcxp_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, |
| 106 | u32 *dm_len) |
| 107 | { |
| 108 | u16 num_fcxp_reqs = cfg->fwcfg.num_fcxp_reqs; |
| 109 | |
| 110 | if (num_fcxp_reqs == 0) |
| 111 | return; |
| 112 | |
| 113 | /* |
| 114 | * Account for req/rsp payload |
| 115 | */ |
| 116 | *dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs; |
| 117 | if (cfg->drvcfg.min_cfg) |
| 118 | *dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs; |
| 119 | else |
| 120 | *dm_len += BFA_FCXP_MAX_LBUF_SZ * num_fcxp_reqs; |
| 121 | |
| 122 | /* |
| 123 | * Account for fcxp structs |
| 124 | */ |
| 125 | *ndm_len += sizeof(struct bfa_fcxp_s) * num_fcxp_reqs; |
| 126 | } |
| 127 | |
| 128 | static void |
| 129 | bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, |
| 130 | struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) |
| 131 | { |
| 132 | struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); |
| 133 | |
| 134 | bfa_os_memset(mod, 0, sizeof(struct bfa_fcxp_mod_s)); |
| 135 | mod->bfa = bfa; |
| 136 | mod->num_fcxps = cfg->fwcfg.num_fcxp_reqs; |
| 137 | |
| 138 | /** |
| 139 | * Initialize FCXP request and response payload sizes. |
| 140 | */ |
| 141 | mod->req_pld_sz = mod->rsp_pld_sz = BFA_FCXP_MAX_IBUF_SZ; |
| 142 | if (!cfg->drvcfg.min_cfg) |
| 143 | mod->rsp_pld_sz = BFA_FCXP_MAX_LBUF_SZ; |
| 144 | |
| 145 | INIT_LIST_HEAD(&mod->wait_q); |
| 146 | |
| 147 | claim_fcxp_req_rsp_mem(mod, meminfo); |
| 148 | claim_fcxps_mem(mod, meminfo); |
| 149 | } |
| 150 | |
| 151 | static void |
| 152 | bfa_fcxp_initdone(struct bfa_s *bfa) |
| 153 | { |
| 154 | } |
| 155 | |
| 156 | static void |
| 157 | bfa_fcxp_detach(struct bfa_s *bfa) |
| 158 | { |
| 159 | } |
| 160 | |
| 161 | static void |
| 162 | bfa_fcxp_start(struct bfa_s *bfa) |
| 163 | { |
| 164 | } |
| 165 | |
| 166 | static void |
| 167 | bfa_fcxp_stop(struct bfa_s *bfa) |
| 168 | { |
| 169 | } |
| 170 | |
| 171 | static void |
| 172 | bfa_fcxp_iocdisable(struct bfa_s *bfa) |
| 173 | { |
| 174 | struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); |
| 175 | struct bfa_fcxp_s *fcxp; |
| 176 | struct list_head *qe, *qen; |
| 177 | |
| 178 | list_for_each_safe(qe, qen, &mod->fcxp_active_q) { |
| 179 | fcxp = (struct bfa_fcxp_s *) qe; |
| 180 | if (fcxp->caller == NULL) { |
| 181 | fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg, |
| 182 | BFA_STATUS_IOC_FAILURE, 0, 0, NULL); |
| 183 | bfa_fcxp_free(fcxp); |
| 184 | } else { |
| 185 | fcxp->rsp_status = BFA_STATUS_IOC_FAILURE; |
| 186 | bfa_cb_queue(bfa, &fcxp->hcb_qe, |
| 187 | __bfa_fcxp_send_cbfn, fcxp); |
| 188 | } |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | static struct bfa_fcxp_s * |
| 193 | bfa_fcxp_get(struct bfa_fcxp_mod_s *fm) |
| 194 | { |
| 195 | struct bfa_fcxp_s *fcxp; |
| 196 | |
| 197 | bfa_q_deq(&fm->fcxp_free_q, &fcxp); |
| 198 | |
| 199 | if (fcxp) |
| 200 | list_add_tail(&fcxp->qe, &fm->fcxp_active_q); |
| 201 | |
Jing Huang | f8ceafd | 2009-09-25 12:29:54 -0700 | [diff] [blame^] | 202 | return fcxp; |
Jing Huang | 7725ccf | 2009-09-23 17:46:15 -0700 | [diff] [blame] | 203 | } |
| 204 | |
| 205 | static void |
| 206 | bfa_fcxp_put(struct bfa_fcxp_s *fcxp) |
| 207 | { |
| 208 | struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; |
| 209 | struct bfa_fcxp_wqe_s *wqe; |
| 210 | |
| 211 | bfa_q_deq(&mod->wait_q, &wqe); |
| 212 | if (wqe) { |
| 213 | bfa_trc(mod->bfa, fcxp->fcxp_tag); |
| 214 | wqe->alloc_cbfn(wqe->alloc_cbarg, fcxp); |
| 215 | return; |
| 216 | } |
| 217 | |
| 218 | bfa_assert(bfa_q_is_on_q(&mod->fcxp_active_q, fcxp)); |
| 219 | list_del(&fcxp->qe); |
| 220 | list_add_tail(&fcxp->qe, &mod->fcxp_free_q); |
| 221 | } |
| 222 | |
| 223 | static void |
| 224 | bfa_fcxp_null_comp(void *bfad_fcxp, struct bfa_fcxp_s *fcxp, void *cbarg, |
| 225 | bfa_status_t req_status, u32 rsp_len, |
| 226 | u32 resid_len, struct fchs_s *rsp_fchs) |
| 227 | { |
| 228 | /**discarded fcxp completion */ |
| 229 | } |
| 230 | |
| 231 | static void |
| 232 | __bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete) |
| 233 | { |
| 234 | struct bfa_fcxp_s *fcxp = cbarg; |
| 235 | |
| 236 | if (complete) { |
| 237 | fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg, |
| 238 | fcxp->rsp_status, fcxp->rsp_len, |
| 239 | fcxp->residue_len, &fcxp->rsp_fchs); |
| 240 | } else { |
| 241 | bfa_fcxp_free(fcxp); |
| 242 | } |
| 243 | } |
| 244 | |
| 245 | static void |
| 246 | hal_fcxp_send_comp(struct bfa_s *bfa, struct bfi_fcxp_send_rsp_s *fcxp_rsp) |
| 247 | { |
| 248 | struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); |
| 249 | struct bfa_fcxp_s *fcxp; |
| 250 | u16 fcxp_tag = bfa_os_ntohs(fcxp_rsp->fcxp_tag); |
| 251 | |
| 252 | bfa_trc(bfa, fcxp_tag); |
| 253 | |
| 254 | fcxp_rsp->rsp_len = bfa_os_ntohl(fcxp_rsp->rsp_len); |
| 255 | |
| 256 | /** |
| 257 | * @todo f/w should not set residue to non-0 when everything |
| 258 | * is received. |
| 259 | */ |
| 260 | if (fcxp_rsp->req_status == BFA_STATUS_OK) |
| 261 | fcxp_rsp->residue_len = 0; |
| 262 | else |
| 263 | fcxp_rsp->residue_len = bfa_os_ntohl(fcxp_rsp->residue_len); |
| 264 | |
| 265 | fcxp = BFA_FCXP_FROM_TAG(mod, fcxp_tag); |
| 266 | |
| 267 | bfa_assert(fcxp->send_cbfn != NULL); |
| 268 | |
| 269 | hal_fcxp_rx_plog(mod->bfa, fcxp, fcxp_rsp); |
| 270 | |
| 271 | if (fcxp->send_cbfn != NULL) { |
| 272 | if (fcxp->caller == NULL) { |
| 273 | bfa_trc(mod->bfa, fcxp->fcxp_tag); |
| 274 | |
| 275 | fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg, |
| 276 | fcxp_rsp->req_status, fcxp_rsp->rsp_len, |
| 277 | fcxp_rsp->residue_len, &fcxp_rsp->fchs); |
| 278 | /* |
| 279 | * fcxp automatically freed on return from the callback |
| 280 | */ |
| 281 | bfa_fcxp_free(fcxp); |
| 282 | } else { |
| 283 | bfa_trc(mod->bfa, fcxp->fcxp_tag); |
| 284 | fcxp->rsp_status = fcxp_rsp->req_status; |
| 285 | fcxp->rsp_len = fcxp_rsp->rsp_len; |
| 286 | fcxp->residue_len = fcxp_rsp->residue_len; |
| 287 | fcxp->rsp_fchs = fcxp_rsp->fchs; |
| 288 | |
| 289 | bfa_cb_queue(bfa, &fcxp->hcb_qe, |
| 290 | __bfa_fcxp_send_cbfn, fcxp); |
| 291 | } |
| 292 | } else { |
| 293 | bfa_trc(bfa, fcxp_tag); |
| 294 | } |
| 295 | } |
| 296 | |
| 297 | static void |
| 298 | hal_fcxp_set_local_sges(struct bfi_sge_s *sge, u32 reqlen, u64 req_pa) |
| 299 | { |
| 300 | union bfi_addr_u sga_zero = { {0} }; |
| 301 | |
| 302 | sge->sg_len = reqlen; |
| 303 | sge->flags = BFI_SGE_DATA_LAST; |
| 304 | bfa_dma_addr_set(sge[0].sga, req_pa); |
| 305 | bfa_sge_to_be(sge); |
| 306 | sge++; |
| 307 | |
| 308 | sge->sga = sga_zero; |
| 309 | sge->sg_len = reqlen; |
| 310 | sge->flags = BFI_SGE_PGDLEN; |
| 311 | bfa_sge_to_be(sge); |
| 312 | } |
| 313 | |
| 314 | static void |
| 315 | hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen, struct bfa_fcxp_s *fcxp, |
| 316 | struct fchs_s *fchs) |
| 317 | { |
| 318 | /* |
| 319 | * TODO: TX ox_id |
| 320 | */ |
| 321 | if (reqlen > 0) { |
| 322 | if (fcxp->use_ireqbuf) { |
| 323 | u32 pld_w0 = |
| 324 | *((u32 *) BFA_FCXP_REQ_PLD(fcxp)); |
| 325 | |
| 326 | bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP, |
| 327 | BFA_PL_EID_TX, |
| 328 | reqlen + sizeof(struct fchs_s), fchs, pld_w0); |
| 329 | } else { |
| 330 | bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, |
| 331 | BFA_PL_EID_TX, reqlen + sizeof(struct fchs_s), |
| 332 | fchs); |
| 333 | } |
| 334 | } else { |
| 335 | bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_TX, |
| 336 | reqlen + sizeof(struct fchs_s), fchs); |
| 337 | } |
| 338 | } |
| 339 | |
| 340 | static void |
| 341 | hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp, |
| 342 | struct bfi_fcxp_send_rsp_s *fcxp_rsp) |
| 343 | { |
| 344 | if (fcxp_rsp->rsp_len > 0) { |
| 345 | if (fcxp->use_irspbuf) { |
| 346 | u32 pld_w0 = |
| 347 | *((u32 *) BFA_FCXP_RSP_PLD(fcxp)); |
| 348 | |
| 349 | bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP, |
| 350 | BFA_PL_EID_RX, |
| 351 | (u16) fcxp_rsp->rsp_len, |
| 352 | &fcxp_rsp->fchs, pld_w0); |
| 353 | } else { |
| 354 | bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, |
| 355 | BFA_PL_EID_RX, |
| 356 | (u16) fcxp_rsp->rsp_len, |
| 357 | &fcxp_rsp->fchs); |
| 358 | } |
| 359 | } else { |
| 360 | bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_RX, |
| 361 | (u16) fcxp_rsp->rsp_len, &fcxp_rsp->fchs); |
| 362 | } |
| 363 | } |
| 364 | |
| 365 | /** |
| 366 | * Handler to resume sending fcxp when space in available in cpe queue. |
| 367 | */ |
| 368 | static void |
| 369 | bfa_fcxp_qresume(void *cbarg) |
| 370 | { |
| 371 | struct bfa_fcxp_s *fcxp = cbarg; |
| 372 | struct bfa_s *bfa = fcxp->fcxp_mod->bfa; |
| 373 | struct bfi_fcxp_send_req_s *send_req; |
| 374 | |
| 375 | fcxp->reqq_waiting = BFA_FALSE; |
| 376 | send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP); |
| 377 | bfa_fcxp_queue(fcxp, send_req); |
| 378 | } |
| 379 | |
| 380 | /** |
| 381 | * Queue fcxp send request to foimrware. |
| 382 | */ |
| 383 | static void |
| 384 | bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req) |
| 385 | { |
| 386 | struct bfa_s *bfa = fcxp->fcxp_mod->bfa; |
| 387 | struct bfa_fcxp_req_info_s *reqi = &fcxp->req_info; |
| 388 | struct bfa_fcxp_rsp_info_s *rspi = &fcxp->rsp_info; |
| 389 | struct bfa_rport_s *rport = reqi->bfa_rport; |
| 390 | |
| 391 | bfi_h2i_set(send_req->mh, BFI_MC_FCXP, BFI_FCXP_H2I_SEND_REQ, |
| 392 | bfa_lpuid(bfa)); |
| 393 | |
| 394 | send_req->fcxp_tag = bfa_os_htons(fcxp->fcxp_tag); |
| 395 | if (rport) { |
| 396 | send_req->rport_fw_hndl = rport->fw_handle; |
| 397 | send_req->max_frmsz = bfa_os_htons(rport->rport_info.max_frmsz); |
| 398 | if (send_req->max_frmsz == 0) |
| 399 | send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ); |
| 400 | } else { |
| 401 | send_req->rport_fw_hndl = 0; |
| 402 | send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ); |
| 403 | } |
| 404 | |
| 405 | send_req->vf_id = bfa_os_htons(reqi->vf_id); |
| 406 | send_req->lp_tag = reqi->lp_tag; |
| 407 | send_req->class = reqi->class; |
| 408 | send_req->rsp_timeout = rspi->rsp_timeout; |
| 409 | send_req->cts = reqi->cts; |
| 410 | send_req->fchs = reqi->fchs; |
| 411 | |
| 412 | send_req->req_len = bfa_os_htonl(reqi->req_tot_len); |
| 413 | send_req->rsp_maxlen = bfa_os_htonl(rspi->rsp_maxlen); |
| 414 | |
| 415 | /* |
| 416 | * setup req sgles |
| 417 | */ |
| 418 | if (fcxp->use_ireqbuf == 1) { |
| 419 | hal_fcxp_set_local_sges(send_req->req_sge, reqi->req_tot_len, |
| 420 | BFA_FCXP_REQ_PLD_PA(fcxp)); |
| 421 | } else { |
| 422 | if (fcxp->nreq_sgles > 0) { |
| 423 | bfa_assert(fcxp->nreq_sgles == 1); |
| 424 | hal_fcxp_set_local_sges(send_req->req_sge, |
| 425 | reqi->req_tot_len, |
| 426 | fcxp->req_sga_cbfn(fcxp->caller, |
| 427 | 0)); |
| 428 | } else { |
| 429 | bfa_assert(reqi->req_tot_len == 0); |
| 430 | hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0); |
| 431 | } |
| 432 | } |
| 433 | |
| 434 | /* |
| 435 | * setup rsp sgles |
| 436 | */ |
| 437 | if (fcxp->use_irspbuf == 1) { |
| 438 | bfa_assert(rspi->rsp_maxlen <= BFA_FCXP_MAX_LBUF_SZ); |
| 439 | |
| 440 | hal_fcxp_set_local_sges(send_req->rsp_sge, rspi->rsp_maxlen, |
| 441 | BFA_FCXP_RSP_PLD_PA(fcxp)); |
| 442 | |
| 443 | } else { |
| 444 | if (fcxp->nrsp_sgles > 0) { |
| 445 | bfa_assert(fcxp->nrsp_sgles == 1); |
| 446 | hal_fcxp_set_local_sges(send_req->rsp_sge, |
| 447 | rspi->rsp_maxlen, |
| 448 | fcxp->rsp_sga_cbfn(fcxp->caller, |
| 449 | 0)); |
| 450 | } else { |
| 451 | bfa_assert(rspi->rsp_maxlen == 0); |
| 452 | hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0); |
| 453 | } |
| 454 | } |
| 455 | |
| 456 | hal_fcxp_tx_plog(bfa, reqi->req_tot_len, fcxp, &reqi->fchs); |
| 457 | |
| 458 | bfa_reqq_produce(bfa, BFA_REQQ_FCXP); |
| 459 | |
| 460 | bfa_trc(bfa, bfa_reqq_pi(bfa, BFA_REQQ_FCXP)); |
| 461 | bfa_trc(bfa, bfa_reqq_ci(bfa, BFA_REQQ_FCXP)); |
| 462 | } |
| 463 | |
| 464 | |
| 465 | /** |
| 466 | * hal_fcxp_api BFA FCXP API |
| 467 | */ |
| 468 | |
| 469 | /** |
| 470 | * Allocate an FCXP instance to send a response or to send a request |
| 471 | * that has a response. Request/response buffers are allocated by caller. |
| 472 | * |
| 473 | * @param[in] bfa BFA bfa instance |
| 474 | * @param[in] nreq_sgles Number of SG elements required for request |
| 475 | * buffer. 0, if fcxp internal buffers are used. |
| 476 | * Use bfa_fcxp_get_reqbuf() to get the |
| 477 | * internal req buffer. |
| 478 | * @param[in] req_sgles SG elements describing request buffer. Will be |
| 479 | * copied in by BFA and hence can be freed on |
| 480 | * return from this function. |
| 481 | * @param[in] get_req_sga function ptr to be called to get a request SG |
| 482 | * Address (given the sge index). |
| 483 | * @param[in] get_req_sglen function ptr to be called to get a request SG |
| 484 | * len (given the sge index). |
| 485 | * @param[in] get_rsp_sga function ptr to be called to get a response SG |
| 486 | * Address (given the sge index). |
| 487 | * @param[in] get_rsp_sglen function ptr to be called to get a response SG |
| 488 | * len (given the sge index). |
| 489 | * |
| 490 | * @return FCXP instance. NULL on failure. |
| 491 | */ |
| 492 | struct bfa_fcxp_s * |
| 493 | bfa_fcxp_alloc(void *caller, struct bfa_s *bfa, int nreq_sgles, |
| 494 | int nrsp_sgles, bfa_fcxp_get_sgaddr_t req_sga_cbfn, |
| 495 | bfa_fcxp_get_sglen_t req_sglen_cbfn, |
| 496 | bfa_fcxp_get_sgaddr_t rsp_sga_cbfn, |
| 497 | bfa_fcxp_get_sglen_t rsp_sglen_cbfn) |
| 498 | { |
| 499 | struct bfa_fcxp_s *fcxp = NULL; |
| 500 | u32 nreq_sgpg, nrsp_sgpg; |
| 501 | |
| 502 | bfa_assert(bfa != NULL); |
| 503 | |
| 504 | fcxp = bfa_fcxp_get(BFA_FCXP_MOD(bfa)); |
| 505 | if (fcxp == NULL) |
Jing Huang | f8ceafd | 2009-09-25 12:29:54 -0700 | [diff] [blame^] | 506 | return NULL; |
Jing Huang | 7725ccf | 2009-09-23 17:46:15 -0700 | [diff] [blame] | 507 | |
| 508 | bfa_trc(bfa, fcxp->fcxp_tag); |
| 509 | |
| 510 | fcxp->caller = caller; |
| 511 | |
| 512 | if (nreq_sgles == 0) { |
| 513 | fcxp->use_ireqbuf = 1; |
| 514 | } else { |
| 515 | bfa_assert(req_sga_cbfn != NULL); |
| 516 | bfa_assert(req_sglen_cbfn != NULL); |
| 517 | |
| 518 | fcxp->use_ireqbuf = 0; |
| 519 | fcxp->req_sga_cbfn = req_sga_cbfn; |
| 520 | fcxp->req_sglen_cbfn = req_sglen_cbfn; |
| 521 | |
| 522 | fcxp->nreq_sgles = nreq_sgles; |
| 523 | |
| 524 | /* |
| 525 | * alloc required sgpgs |
| 526 | */ |
| 527 | if (nreq_sgles > BFI_SGE_INLINE) { |
| 528 | nreq_sgpg = BFA_SGPG_NPAGE(nreq_sgles); |
| 529 | |
| 530 | if (bfa_sgpg_malloc |
| 531 | (bfa, &fcxp->req_sgpg_q, nreq_sgpg) |
| 532 | != BFA_STATUS_OK) { |
| 533 | /* bfa_sgpg_wait(bfa, &fcxp->req_sgpg_wqe, |
| 534 | nreq_sgpg); */ |
| 535 | /* |
| 536 | * TODO |
| 537 | */ |
| 538 | } |
| 539 | } |
| 540 | } |
| 541 | |
| 542 | if (nrsp_sgles == 0) { |
| 543 | fcxp->use_irspbuf = 1; |
| 544 | } else { |
| 545 | bfa_assert(rsp_sga_cbfn != NULL); |
| 546 | bfa_assert(rsp_sglen_cbfn != NULL); |
| 547 | |
| 548 | fcxp->use_irspbuf = 0; |
| 549 | fcxp->rsp_sga_cbfn = rsp_sga_cbfn; |
| 550 | fcxp->rsp_sglen_cbfn = rsp_sglen_cbfn; |
| 551 | |
| 552 | fcxp->nrsp_sgles = nrsp_sgles; |
| 553 | /* |
| 554 | * alloc required sgpgs |
| 555 | */ |
| 556 | if (nrsp_sgles > BFI_SGE_INLINE) { |
| 557 | nrsp_sgpg = BFA_SGPG_NPAGE(nreq_sgles); |
| 558 | |
| 559 | if (bfa_sgpg_malloc |
| 560 | (bfa, &fcxp->rsp_sgpg_q, nrsp_sgpg) |
| 561 | != BFA_STATUS_OK) { |
| 562 | /* bfa_sgpg_wait(bfa, &fcxp->rsp_sgpg_wqe, |
| 563 | nrsp_sgpg); */ |
| 564 | /* |
| 565 | * TODO |
| 566 | */ |
| 567 | } |
| 568 | } |
| 569 | } |
| 570 | |
Jing Huang | f8ceafd | 2009-09-25 12:29:54 -0700 | [diff] [blame^] | 571 | return fcxp; |
Jing Huang | 7725ccf | 2009-09-23 17:46:15 -0700 | [diff] [blame] | 572 | } |
| 573 | |
| 574 | /** |
| 575 | * Get the internal request buffer pointer |
| 576 | * |
| 577 | * @param[in] fcxp BFA fcxp pointer |
| 578 | * |
| 579 | * @return pointer to the internal request buffer |
| 580 | */ |
| 581 | void * |
| 582 | bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp) |
| 583 | { |
| 584 | struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; |
| 585 | void *reqbuf; |
| 586 | |
| 587 | bfa_assert(fcxp->use_ireqbuf == 1); |
| 588 | reqbuf = ((u8 *)mod->req_pld_list_kva) + |
| 589 | fcxp->fcxp_tag * mod->req_pld_sz; |
| 590 | return reqbuf; |
| 591 | } |
| 592 | |
| 593 | u32 |
| 594 | bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp) |
| 595 | { |
| 596 | struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; |
| 597 | |
| 598 | return mod->req_pld_sz; |
| 599 | } |
| 600 | |
| 601 | /** |
| 602 | * Get the internal response buffer pointer |
| 603 | * |
| 604 | * @param[in] fcxp BFA fcxp pointer |
| 605 | * |
| 606 | * @return pointer to the internal request buffer |
| 607 | */ |
| 608 | void * |
| 609 | bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp) |
| 610 | { |
| 611 | struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; |
| 612 | void *rspbuf; |
| 613 | |
| 614 | bfa_assert(fcxp->use_irspbuf == 1); |
| 615 | |
| 616 | rspbuf = ((u8 *)mod->rsp_pld_list_kva) + |
| 617 | fcxp->fcxp_tag * mod->rsp_pld_sz; |
| 618 | return rspbuf; |
| 619 | } |
| 620 | |
| 621 | /** |
| 622 | * Free the BFA FCXP |
| 623 | * |
| 624 | * @param[in] fcxp BFA fcxp pointer |
| 625 | * |
| 626 | * @return void |
| 627 | */ |
| 628 | void |
| 629 | bfa_fcxp_free(struct bfa_fcxp_s *fcxp) |
| 630 | { |
| 631 | struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; |
| 632 | |
| 633 | bfa_assert(fcxp != NULL); |
| 634 | bfa_trc(mod->bfa, fcxp->fcxp_tag); |
| 635 | bfa_fcxp_put(fcxp); |
| 636 | } |
| 637 | |
| 638 | /** |
| 639 | * Send a FCXP request |
| 640 | * |
| 641 | * @param[in] fcxp BFA fcxp pointer |
| 642 | * @param[in] rport BFA rport pointer. Could be left NULL for WKA rports |
| 643 | * @param[in] vf_id virtual Fabric ID |
| 644 | * @param[in] lp_tag lport tag |
| 645 | * @param[in] cts use Continous sequence |
| 646 | * @param[in] cos fc Class of Service |
| 647 | * @param[in] reqlen request length, does not include FCHS length |
| 648 | * @param[in] fchs fc Header Pointer. The header content will be copied |
| 649 | * in by BFA. |
| 650 | * |
| 651 | * @param[in] cbfn call back function to be called on receiving |
| 652 | * the response |
| 653 | * @param[in] cbarg arg for cbfn |
| 654 | * @param[in] rsp_timeout |
| 655 | * response timeout |
| 656 | * |
| 657 | * @return bfa_status_t |
| 658 | */ |
| 659 | void |
| 660 | bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport, |
| 661 | u16 vf_id, u8 lp_tag, bfa_boolean_t cts, enum fc_cos cos, |
| 662 | u32 reqlen, struct fchs_s *fchs, bfa_cb_fcxp_send_t cbfn, |
| 663 | void *cbarg, u32 rsp_maxlen, u8 rsp_timeout) |
| 664 | { |
| 665 | struct bfa_s *bfa = fcxp->fcxp_mod->bfa; |
| 666 | struct bfa_fcxp_req_info_s *reqi = &fcxp->req_info; |
| 667 | struct bfa_fcxp_rsp_info_s *rspi = &fcxp->rsp_info; |
| 668 | struct bfi_fcxp_send_req_s *send_req; |
| 669 | |
| 670 | bfa_trc(bfa, fcxp->fcxp_tag); |
| 671 | |
| 672 | /** |
| 673 | * setup request/response info |
| 674 | */ |
| 675 | reqi->bfa_rport = rport; |
| 676 | reqi->vf_id = vf_id; |
| 677 | reqi->lp_tag = lp_tag; |
| 678 | reqi->class = cos; |
| 679 | rspi->rsp_timeout = rsp_timeout; |
| 680 | reqi->cts = cts; |
| 681 | reqi->fchs = *fchs; |
| 682 | reqi->req_tot_len = reqlen; |
| 683 | rspi->rsp_maxlen = rsp_maxlen; |
| 684 | fcxp->send_cbfn = cbfn ? cbfn : bfa_fcxp_null_comp; |
| 685 | fcxp->send_cbarg = cbarg; |
| 686 | |
| 687 | /** |
| 688 | * If no room in CPE queue, wait for |
| 689 | */ |
| 690 | send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP); |
| 691 | if (!send_req) { |
| 692 | bfa_trc(bfa, fcxp->fcxp_tag); |
| 693 | fcxp->reqq_waiting = BFA_TRUE; |
| 694 | bfa_reqq_wait(bfa, BFA_REQQ_FCXP, &fcxp->reqq_wqe); |
| 695 | return; |
| 696 | } |
| 697 | |
| 698 | bfa_fcxp_queue(fcxp, send_req); |
| 699 | } |
| 700 | |
| 701 | /** |
| 702 | * Abort a BFA FCXP |
| 703 | * |
| 704 | * @param[in] fcxp BFA fcxp pointer |
| 705 | * |
| 706 | * @return void |
| 707 | */ |
| 708 | bfa_status_t |
| 709 | bfa_fcxp_abort(struct bfa_fcxp_s *fcxp) |
| 710 | { |
| 711 | bfa_assert(0); |
Jing Huang | f8ceafd | 2009-09-25 12:29:54 -0700 | [diff] [blame^] | 712 | return BFA_STATUS_OK; |
Jing Huang | 7725ccf | 2009-09-23 17:46:15 -0700 | [diff] [blame] | 713 | } |
| 714 | |
| 715 | void |
| 716 | bfa_fcxp_alloc_wait(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe, |
| 717 | bfa_fcxp_alloc_cbfn_t alloc_cbfn, void *alloc_cbarg) |
| 718 | { |
| 719 | struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); |
| 720 | |
| 721 | bfa_assert(list_empty(&mod->fcxp_free_q)); |
| 722 | |
| 723 | wqe->alloc_cbfn = alloc_cbfn; |
| 724 | wqe->alloc_cbarg = alloc_cbarg; |
| 725 | list_add_tail(&wqe->qe, &mod->wait_q); |
| 726 | } |
| 727 | |
| 728 | void |
| 729 | bfa_fcxp_walloc_cancel(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe) |
| 730 | { |
| 731 | struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); |
| 732 | |
| 733 | bfa_assert(bfa_q_is_on_q(&mod->wait_q, wqe)); |
| 734 | list_del(&wqe->qe); |
| 735 | } |
| 736 | |
| 737 | void |
| 738 | bfa_fcxp_discard(struct bfa_fcxp_s *fcxp) |
| 739 | { |
| 740 | /** |
| 741 | * If waiting for room in request queue, cancel reqq wait |
| 742 | * and free fcxp. |
| 743 | */ |
| 744 | if (fcxp->reqq_waiting) { |
| 745 | fcxp->reqq_waiting = BFA_FALSE; |
| 746 | bfa_reqq_wcancel(&fcxp->reqq_wqe); |
| 747 | bfa_fcxp_free(fcxp); |
| 748 | return; |
| 749 | } |
| 750 | |
| 751 | fcxp->send_cbfn = bfa_fcxp_null_comp; |
| 752 | } |
| 753 | |
| 754 | |
| 755 | |
| 756 | /** |
| 757 | * hal_fcxp_public BFA FCXP public functions |
| 758 | */ |
| 759 | |
| 760 | void |
| 761 | bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) |
| 762 | { |
| 763 | switch (msg->mhdr.msg_id) { |
| 764 | case BFI_FCXP_I2H_SEND_RSP: |
| 765 | hal_fcxp_send_comp(bfa, (struct bfi_fcxp_send_rsp_s *) msg); |
| 766 | break; |
| 767 | |
| 768 | default: |
| 769 | bfa_trc(bfa, msg->mhdr.msg_id); |
| 770 | bfa_assert(0); |
| 771 | } |
| 772 | } |
| 773 | |
| 774 | u32 |
| 775 | bfa_fcxp_get_maxrsp(struct bfa_s *bfa) |
| 776 | { |
| 777 | struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); |
| 778 | |
| 779 | return mod->rsp_pld_sz; |
| 780 | } |
| 781 | |
| 782 | |