diff options
Diffstat (limited to 'drivers/scsi/bfa/bfa_fcxp.c')
-rw-r--r-- | drivers/scsi/bfa/bfa_fcxp.c | 782 |
1 files changed, 782 insertions, 0 deletions
diff --git a/drivers/scsi/bfa/bfa_fcxp.c b/drivers/scsi/bfa/bfa_fcxp.c new file mode 100644 index 000000000000..4754a0e9006a --- /dev/null +++ b/drivers/scsi/bfa/bfa_fcxp.c | |||
@@ -0,0 +1,782 @@ | |||
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 | |||
202 | return (fcxp); | ||
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) | ||
506 | return (NULL); | ||
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 | |||
571 | return (fcxp); | ||
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); | ||
712 | return (BFA_STATUS_OK); | ||
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 | |||