Commit | Line | Data |
---|---|---|
7725ccfd JH |
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 <cs/bfa_debug.h> | |
19 | #include <bfa_priv.h> | |
20 | #include <log/bfa_log_hal.h> | |
21 | #include <bfi/bfi_boot.h> | |
22 | #include <bfi/bfi_cbreg.h> | |
23 | #include <aen/bfa_aen_ioc.h> | |
24 | #include <defs/bfa_defs_iocfc.h> | |
25 | #include <defs/bfa_defs_pci.h> | |
26 | #include "bfa_callback_priv.h" | |
27 | #include "bfad_drv.h" | |
28 | ||
29 | BFA_TRC_FILE(HAL, IOCFC); | |
30 | ||
31 | /** | |
32 | * IOC local definitions | |
33 | */ | |
34 | #define BFA_IOCFC_TOV 5000 /* msecs */ | |
35 | ||
36 | enum { | |
37 | BFA_IOCFC_ACT_NONE = 0, | |
38 | BFA_IOCFC_ACT_INIT = 1, | |
39 | BFA_IOCFC_ACT_STOP = 2, | |
40 | BFA_IOCFC_ACT_DISABLE = 3, | |
41 | }; | |
42 | ||
43 | /* | |
44 | * forward declarations | |
45 | */ | |
46 | static void bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status); | |
47 | static void bfa_iocfc_disable_cbfn(void *bfa_arg); | |
48 | static void bfa_iocfc_hbfail_cbfn(void *bfa_arg); | |
49 | static void bfa_iocfc_reset_cbfn(void *bfa_arg); | |
50 | static void bfa_iocfc_stats_clear(void *bfa_arg); | |
51 | static void bfa_iocfc_stats_swap(struct bfa_fw_stats_s *d, | |
52 | struct bfa_fw_stats_s *s); | |
53 | static void bfa_iocfc_stats_clr_cb(void *bfa_arg, bfa_boolean_t complete); | |
54 | static void bfa_iocfc_stats_clr_timeout(void *bfa_arg); | |
55 | static void bfa_iocfc_stats_cb(void *bfa_arg, bfa_boolean_t complete); | |
56 | static void bfa_iocfc_stats_timeout(void *bfa_arg); | |
57 | ||
58 | static struct bfa_ioc_cbfn_s bfa_iocfc_cbfn; | |
59 | ||
60 | /** | |
61 | * bfa_ioc_pvt BFA IOC private functions | |
62 | */ | |
63 | ||
64 | static void | |
65 | bfa_iocfc_cqs_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len) | |
66 | { | |
67 | int i, per_reqq_sz, per_rspq_sz; | |
68 | ||
69 | per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ), | |
70 | BFA_DMA_ALIGN_SZ); | |
71 | per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ), | |
72 | BFA_DMA_ALIGN_SZ); | |
73 | ||
74 | /* | |
75 | * Calculate CQ size | |
76 | */ | |
77 | for (i = 0; i < cfg->fwcfg.num_cqs; i++) { | |
78 | *dm_len = *dm_len + per_reqq_sz; | |
79 | *dm_len = *dm_len + per_rspq_sz; | |
80 | } | |
81 | ||
82 | /* | |
83 | * Calculate Shadow CI/PI size | |
84 | */ | |
85 | for (i = 0; i < cfg->fwcfg.num_cqs; i++) | |
86 | *dm_len += (2 * BFA_CACHELINE_SZ); | |
87 | } | |
88 | ||
89 | static void | |
90 | bfa_iocfc_fw_cfg_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len) | |
91 | { | |
92 | *dm_len += | |
93 | BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); | |
94 | *dm_len += | |
95 | BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), | |
96 | BFA_CACHELINE_SZ); | |
97 | *dm_len += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ); | |
98 | } | |
99 | ||
100 | /** | |
101 | * Use the Mailbox interface to send BFI_IOCFC_H2I_CFG_REQ | |
102 | */ | |
103 | static void | |
104 | bfa_iocfc_send_cfg(void *bfa_arg) | |
105 | { | |
106 | struct bfa_s *bfa = bfa_arg; | |
107 | struct bfa_iocfc_s *iocfc = &bfa->iocfc; | |
108 | struct bfi_iocfc_cfg_req_s cfg_req; | |
109 | struct bfi_iocfc_cfg_s *cfg_info = iocfc->cfginfo; | |
110 | struct bfa_iocfc_cfg_s *cfg = &iocfc->cfg; | |
111 | int i; | |
112 | ||
113 | bfa_assert(cfg->fwcfg.num_cqs <= BFI_IOC_MAX_CQS); | |
114 | bfa_trc(bfa, cfg->fwcfg.num_cqs); | |
115 | ||
116 | iocfc->cfgdone = BFA_FALSE; | |
117 | bfa_iocfc_reset_queues(bfa); | |
118 | ||
119 | /** | |
120 | * initialize IOC configuration info | |
121 | */ | |
122 | cfg_info->endian_sig = BFI_IOC_ENDIAN_SIG; | |
123 | cfg_info->num_cqs = cfg->fwcfg.num_cqs; | |
124 | ||
125 | bfa_dma_be_addr_set(cfg_info->cfgrsp_addr, iocfc->cfgrsp_dma.pa); | |
126 | bfa_dma_be_addr_set(cfg_info->stats_addr, iocfc->stats_pa); | |
127 | ||
128 | /** | |
129 | * dma map REQ and RSP circular queues and shadow pointers | |
130 | */ | |
131 | for (i = 0; i < cfg->fwcfg.num_cqs; i++) { | |
132 | bfa_dma_be_addr_set(cfg_info->req_cq_ba[i], | |
133 | iocfc->req_cq_ba[i].pa); | |
134 | bfa_dma_be_addr_set(cfg_info->req_shadow_ci[i], | |
135 | iocfc->req_cq_shadow_ci[i].pa); | |
136 | cfg_info->req_cq_elems[i] = | |
137 | bfa_os_htons(cfg->drvcfg.num_reqq_elems); | |
138 | ||
139 | bfa_dma_be_addr_set(cfg_info->rsp_cq_ba[i], | |
140 | iocfc->rsp_cq_ba[i].pa); | |
141 | bfa_dma_be_addr_set(cfg_info->rsp_shadow_pi[i], | |
142 | iocfc->rsp_cq_shadow_pi[i].pa); | |
143 | cfg_info->rsp_cq_elems[i] = | |
144 | bfa_os_htons(cfg->drvcfg.num_rspq_elems); | |
145 | } | |
146 | ||
147 | /** | |
148 | * dma map IOC configuration itself | |
149 | */ | |
150 | bfi_h2i_set(cfg_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CFG_REQ, | |
151 | bfa_lpuid(bfa)); | |
152 | bfa_dma_be_addr_set(cfg_req.ioc_cfg_dma_addr, iocfc->cfg_info.pa); | |
153 | ||
154 | bfa_ioc_mbox_send(&bfa->ioc, &cfg_req, | |
155 | sizeof(struct bfi_iocfc_cfg_req_s)); | |
156 | } | |
157 | ||
158 | static void | |
159 | bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, | |
160 | struct bfa_pcidev_s *pcidev) | |
161 | { | |
162 | struct bfa_iocfc_s *iocfc = &bfa->iocfc; | |
163 | ||
164 | bfa->bfad = bfad; | |
165 | iocfc->bfa = bfa; | |
166 | iocfc->action = BFA_IOCFC_ACT_NONE; | |
167 | ||
168 | bfa_os_assign(iocfc->cfg, *cfg); | |
169 | ||
170 | /** | |
171 | * Initialize chip specific handlers. | |
172 | */ | |
173 | if (bfa_ioc_devid(&bfa->ioc) == BFA_PCI_DEVICE_ID_CT) { | |
174 | iocfc->hwif.hw_reginit = bfa_hwct_reginit; | |
175 | iocfc->hwif.hw_rspq_ack = bfa_hwct_rspq_ack; | |
176 | iocfc->hwif.hw_msix_init = bfa_hwct_msix_init; | |
177 | iocfc->hwif.hw_msix_install = bfa_hwct_msix_install; | |
178 | iocfc->hwif.hw_msix_uninstall = bfa_hwct_msix_uninstall; | |
179 | iocfc->hwif.hw_isr_mode_set = bfa_hwct_isr_mode_set; | |
180 | iocfc->hwif.hw_msix_getvecs = bfa_hwct_msix_getvecs; | |
181 | } else { | |
182 | iocfc->hwif.hw_reginit = bfa_hwcb_reginit; | |
183 | iocfc->hwif.hw_rspq_ack = bfa_hwcb_rspq_ack; | |
184 | iocfc->hwif.hw_msix_init = bfa_hwcb_msix_init; | |
185 | iocfc->hwif.hw_msix_install = bfa_hwcb_msix_install; | |
186 | iocfc->hwif.hw_msix_uninstall = bfa_hwcb_msix_uninstall; | |
187 | iocfc->hwif.hw_isr_mode_set = bfa_hwcb_isr_mode_set; | |
188 | iocfc->hwif.hw_msix_getvecs = bfa_hwcb_msix_getvecs; | |
189 | } | |
190 | ||
191 | iocfc->hwif.hw_reginit(bfa); | |
192 | bfa->msix.nvecs = 0; | |
193 | } | |
194 | ||
195 | static void | |
196 | bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg, | |
197 | struct bfa_meminfo_s *meminfo) | |
198 | { | |
199 | u8 *dm_kva; | |
200 | u64 dm_pa; | |
201 | int i, per_reqq_sz, per_rspq_sz; | |
202 | struct bfa_iocfc_s *iocfc = &bfa->iocfc; | |
203 | int dbgsz; | |
204 | ||
205 | dm_kva = bfa_meminfo_dma_virt(meminfo); | |
206 | dm_pa = bfa_meminfo_dma_phys(meminfo); | |
207 | ||
208 | /* | |
209 | * First allocate dma memory for IOC. | |
210 | */ | |
211 | bfa_ioc_mem_claim(&bfa->ioc, dm_kva, dm_pa); | |
212 | dm_kva += bfa_ioc_meminfo(); | |
213 | dm_pa += bfa_ioc_meminfo(); | |
214 | ||
215 | /* | |
216 | * Claim DMA-able memory for the request/response queues and for shadow | |
217 | * ci/pi registers | |
218 | */ | |
219 | per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ), | |
220 | BFA_DMA_ALIGN_SZ); | |
221 | per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ), | |
222 | BFA_DMA_ALIGN_SZ); | |
223 | ||
224 | for (i = 0; i < cfg->fwcfg.num_cqs; i++) { | |
225 | iocfc->req_cq_ba[i].kva = dm_kva; | |
226 | iocfc->req_cq_ba[i].pa = dm_pa; | |
227 | bfa_os_memset(dm_kva, 0, per_reqq_sz); | |
228 | dm_kva += per_reqq_sz; | |
229 | dm_pa += per_reqq_sz; | |
230 | ||
231 | iocfc->rsp_cq_ba[i].kva = dm_kva; | |
232 | iocfc->rsp_cq_ba[i].pa = dm_pa; | |
233 | bfa_os_memset(dm_kva, 0, per_rspq_sz); | |
234 | dm_kva += per_rspq_sz; | |
235 | dm_pa += per_rspq_sz; | |
236 | } | |
237 | ||
238 | for (i = 0; i < cfg->fwcfg.num_cqs; i++) { | |
239 | iocfc->req_cq_shadow_ci[i].kva = dm_kva; | |
240 | iocfc->req_cq_shadow_ci[i].pa = dm_pa; | |
241 | dm_kva += BFA_CACHELINE_SZ; | |
242 | dm_pa += BFA_CACHELINE_SZ; | |
243 | ||
244 | iocfc->rsp_cq_shadow_pi[i].kva = dm_kva; | |
245 | iocfc->rsp_cq_shadow_pi[i].pa = dm_pa; | |
246 | dm_kva += BFA_CACHELINE_SZ; | |
247 | dm_pa += BFA_CACHELINE_SZ; | |
248 | } | |
249 | ||
250 | /* | |
251 | * Claim DMA-able memory for the config info page | |
252 | */ | |
253 | bfa->iocfc.cfg_info.kva = dm_kva; | |
254 | bfa->iocfc.cfg_info.pa = dm_pa; | |
255 | bfa->iocfc.cfginfo = (struct bfi_iocfc_cfg_s *) dm_kva; | |
256 | dm_kva += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); | |
257 | dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); | |
258 | ||
259 | /* | |
260 | * Claim DMA-able memory for the config response | |
261 | */ | |
262 | bfa->iocfc.cfgrsp_dma.kva = dm_kva; | |
263 | bfa->iocfc.cfgrsp_dma.pa = dm_pa; | |
264 | bfa->iocfc.cfgrsp = (struct bfi_iocfc_cfgrsp_s *) dm_kva; | |
265 | ||
266 | dm_kva += | |
267 | BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), | |
268 | BFA_CACHELINE_SZ); | |
269 | dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), | |
270 | BFA_CACHELINE_SZ); | |
271 | ||
272 | /* | |
273 | * Claim DMA-able memory for iocfc stats | |
274 | */ | |
275 | bfa->iocfc.stats_kva = dm_kva; | |
276 | bfa->iocfc.stats_pa = dm_pa; | |
277 | bfa->iocfc.fw_stats = (struct bfa_fw_stats_s *) dm_kva; | |
278 | dm_kva += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ); | |
279 | dm_pa += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ); | |
280 | ||
281 | bfa_meminfo_dma_virt(meminfo) = dm_kva; | |
282 | bfa_meminfo_dma_phys(meminfo) = dm_pa; | |
283 | ||
284 | dbgsz = bfa_ioc_debug_trcsz(bfa_auto_recover); | |
285 | if (dbgsz > 0) { | |
286 | bfa_ioc_debug_memclaim(&bfa->ioc, bfa_meminfo_kva(meminfo)); | |
287 | bfa_meminfo_kva(meminfo) += dbgsz; | |
288 | } | |
289 | } | |
290 | ||
291 | /** | |
292 | * BFA submodules initialization completion notification. | |
293 | */ | |
294 | static void | |
295 | bfa_iocfc_initdone_submod(struct bfa_s *bfa) | |
296 | { | |
297 | int i; | |
298 | ||
299 | for (i = 0; hal_mods[i]; i++) | |
300 | hal_mods[i]->initdone(bfa); | |
301 | } | |
302 | ||
303 | /** | |
304 | * Start BFA submodules. | |
305 | */ | |
306 | static void | |
307 | bfa_iocfc_start_submod(struct bfa_s *bfa) | |
308 | { | |
309 | int i; | |
310 | ||
311 | bfa->rme_process = BFA_TRUE; | |
312 | ||
313 | for (i = 0; hal_mods[i]; i++) | |
314 | hal_mods[i]->start(bfa); | |
315 | } | |
316 | ||
317 | /** | |
318 | * Disable BFA submodules. | |
319 | */ | |
320 | static void | |
321 | bfa_iocfc_disable_submod(struct bfa_s *bfa) | |
322 | { | |
323 | int i; | |
324 | ||
325 | for (i = 0; hal_mods[i]; i++) | |
326 | hal_mods[i]->iocdisable(bfa); | |
327 | } | |
328 | ||
329 | static void | |
330 | bfa_iocfc_init_cb(void *bfa_arg, bfa_boolean_t complete) | |
331 | { | |
332 | struct bfa_s *bfa = bfa_arg; | |
333 | ||
334 | if (complete) { | |
335 | if (bfa->iocfc.cfgdone) | |
336 | bfa_cb_init(bfa->bfad, BFA_STATUS_OK); | |
337 | else | |
338 | bfa_cb_init(bfa->bfad, BFA_STATUS_FAILED); | |
339 | } else | |
340 | bfa->iocfc.action = BFA_IOCFC_ACT_NONE; | |
341 | } | |
342 | ||
343 | static void | |
344 | bfa_iocfc_stop_cb(void *bfa_arg, bfa_boolean_t compl) | |
345 | { | |
346 | struct bfa_s *bfa = bfa_arg; | |
347 | struct bfad_s *bfad = bfa->bfad; | |
348 | ||
349 | if (compl) | |
350 | complete(&bfad->comp); | |
351 | ||
352 | else | |
353 | bfa->iocfc.action = BFA_IOCFC_ACT_NONE; | |
354 | } | |
355 | ||
356 | static void | |
357 | bfa_iocfc_disable_cb(void *bfa_arg, bfa_boolean_t compl) | |
358 | { | |
359 | struct bfa_s *bfa = bfa_arg; | |
360 | struct bfad_s *bfad = bfa->bfad; | |
361 | ||
362 | if (compl) | |
363 | complete(&bfad->disable_comp); | |
364 | } | |
365 | ||
366 | /** | |
367 | * Update BFA configuration from firmware configuration. | |
368 | */ | |
369 | static void | |
370 | bfa_iocfc_cfgrsp(struct bfa_s *bfa) | |
371 | { | |
372 | struct bfa_iocfc_s *iocfc = &bfa->iocfc; | |
373 | struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; | |
374 | struct bfa_iocfc_fwcfg_s *fwcfg = &cfgrsp->fwcfg; | |
375 | struct bfi_iocfc_cfg_s *cfginfo = iocfc->cfginfo; | |
376 | ||
377 | fwcfg->num_cqs = fwcfg->num_cqs; | |
378 | fwcfg->num_ioim_reqs = bfa_os_ntohs(fwcfg->num_ioim_reqs); | |
379 | fwcfg->num_tskim_reqs = bfa_os_ntohs(fwcfg->num_tskim_reqs); | |
380 | fwcfg->num_fcxp_reqs = bfa_os_ntohs(fwcfg->num_fcxp_reqs); | |
381 | fwcfg->num_uf_bufs = bfa_os_ntohs(fwcfg->num_uf_bufs); | |
382 | fwcfg->num_rports = bfa_os_ntohs(fwcfg->num_rports); | |
383 | ||
384 | cfginfo->intr_attr.coalesce = cfgrsp->intr_attr.coalesce; | |
385 | cfginfo->intr_attr.delay = bfa_os_ntohs(cfgrsp->intr_attr.delay); | |
386 | cfginfo->intr_attr.latency = bfa_os_ntohs(cfgrsp->intr_attr.latency); | |
387 | ||
388 | iocfc->cfgdone = BFA_TRUE; | |
389 | ||
390 | /** | |
391 | * Configuration is complete - initialize/start submodules | |
392 | */ | |
393 | if (iocfc->action == BFA_IOCFC_ACT_INIT) | |
394 | bfa_cb_queue(bfa, &iocfc->init_hcb_qe, bfa_iocfc_init_cb, bfa); | |
395 | else | |
396 | bfa_iocfc_start_submod(bfa); | |
397 | } | |
398 | ||
399 | static void | |
400 | bfa_iocfc_stats_clear(void *bfa_arg) | |
401 | { | |
402 | struct bfa_s *bfa = bfa_arg; | |
403 | struct bfa_iocfc_s *iocfc = &bfa->iocfc; | |
404 | struct bfi_iocfc_stats_req_s stats_req; | |
405 | ||
406 | bfa_timer_start(bfa, &iocfc->stats_timer, | |
407 | bfa_iocfc_stats_clr_timeout, bfa, | |
408 | BFA_IOCFC_TOV); | |
409 | ||
410 | bfi_h2i_set(stats_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CLEAR_STATS_REQ, | |
411 | bfa_lpuid(bfa)); | |
412 | bfa_ioc_mbox_send(&bfa->ioc, &stats_req, | |
413 | sizeof(struct bfi_iocfc_stats_req_s)); | |
414 | } | |
415 | ||
416 | static void | |
417 | bfa_iocfc_stats_swap(struct bfa_fw_stats_s *d, struct bfa_fw_stats_s *s) | |
418 | { | |
419 | u32 *dip = (u32 *) d; | |
420 | u32 *sip = (u32 *) s; | |
421 | int i; | |
422 | ||
423 | for (i = 0; i < (sizeof(struct bfa_fw_stats_s) / sizeof(u32)); i++) | |
424 | dip[i] = bfa_os_ntohl(sip[i]); | |
425 | } | |
426 | ||
427 | static void | |
428 | bfa_iocfc_stats_clr_cb(void *bfa_arg, bfa_boolean_t complete) | |
429 | { | |
430 | struct bfa_s *bfa = bfa_arg; | |
431 | struct bfa_iocfc_s *iocfc = &bfa->iocfc; | |
432 | ||
433 | if (complete) { | |
434 | bfa_ioc_clr_stats(&bfa->ioc); | |
435 | iocfc->stats_cbfn(iocfc->stats_cbarg, iocfc->stats_status); | |
436 | } else { | |
437 | iocfc->stats_busy = BFA_FALSE; | |
438 | iocfc->stats_status = BFA_STATUS_OK; | |
439 | } | |
440 | } | |
441 | ||
442 | static void | |
443 | bfa_iocfc_stats_clr_timeout(void *bfa_arg) | |
444 | { | |
445 | struct bfa_s *bfa = bfa_arg; | |
446 | struct bfa_iocfc_s *iocfc = &bfa->iocfc; | |
447 | ||
448 | bfa_trc(bfa, 0); | |
449 | ||
450 | iocfc->stats_status = BFA_STATUS_ETIMER; | |
451 | bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_clr_cb, bfa); | |
452 | } | |
453 | ||
454 | static void | |
455 | bfa_iocfc_stats_cb(void *bfa_arg, bfa_boolean_t complete) | |
456 | { | |
457 | struct bfa_s *bfa = bfa_arg; | |
458 | struct bfa_iocfc_s *iocfc = &bfa->iocfc; | |
459 | ||
460 | if (complete) { | |
461 | if (iocfc->stats_status == BFA_STATUS_OK) { | |
462 | bfa_os_memset(iocfc->stats_ret, 0, | |
463 | sizeof(*iocfc->stats_ret)); | |
464 | bfa_iocfc_stats_swap(&iocfc->stats_ret->fw_stats, | |
465 | iocfc->fw_stats); | |
466 | } | |
467 | iocfc->stats_cbfn(iocfc->stats_cbarg, iocfc->stats_status); | |
468 | } else { | |
469 | iocfc->stats_busy = BFA_FALSE; | |
470 | iocfc->stats_status = BFA_STATUS_OK; | |
471 | } | |
472 | } | |
473 | ||
474 | static void | |
475 | bfa_iocfc_stats_timeout(void *bfa_arg) | |
476 | { | |
477 | struct bfa_s *bfa = bfa_arg; | |
478 | struct bfa_iocfc_s *iocfc = &bfa->iocfc; | |
479 | ||
480 | bfa_trc(bfa, 0); | |
481 | ||
482 | iocfc->stats_status = BFA_STATUS_ETIMER; | |
483 | bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_cb, bfa); | |
484 | } | |
485 | ||
486 | static void | |
487 | bfa_iocfc_stats_query(struct bfa_s *bfa) | |
488 | { | |
489 | struct bfa_iocfc_s *iocfc = &bfa->iocfc; | |
490 | struct bfi_iocfc_stats_req_s stats_req; | |
491 | ||
492 | bfa_timer_start(bfa, &iocfc->stats_timer, | |
493 | bfa_iocfc_stats_timeout, bfa, BFA_IOCFC_TOV); | |
494 | ||
495 | bfi_h2i_set(stats_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_GET_STATS_REQ, | |
496 | bfa_lpuid(bfa)); | |
497 | bfa_ioc_mbox_send(&bfa->ioc, &stats_req, | |
498 | sizeof(struct bfi_iocfc_stats_req_s)); | |
499 | } | |
500 | ||
501 | void | |
502 | bfa_iocfc_reset_queues(struct bfa_s *bfa) | |
503 | { | |
504 | int q; | |
505 | ||
506 | for (q = 0; q < BFI_IOC_MAX_CQS; q++) { | |
507 | bfa_reqq_ci(bfa, q) = 0; | |
508 | bfa_reqq_pi(bfa, q) = 0; | |
509 | bfa_rspq_ci(bfa, q) = 0; | |
510 | bfa_rspq_pi(bfa, q) = 0; | |
511 | } | |
512 | } | |
513 | ||
514 | /** | |
515 | * IOC enable request is complete | |
516 | */ | |
517 | static void | |
518 | bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status) | |
519 | { | |
520 | struct bfa_s *bfa = bfa_arg; | |
521 | ||
522 | if (status != BFA_STATUS_OK) { | |
523 | bfa_isr_disable(bfa); | |
524 | if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT) | |
525 | bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe, | |
526 | bfa_iocfc_init_cb, bfa); | |
527 | return; | |
528 | } | |
529 | ||
530 | bfa_iocfc_initdone_submod(bfa); | |
531 | bfa_iocfc_send_cfg(bfa); | |
532 | } | |
533 | ||
534 | /** | |
535 | * IOC disable request is complete | |
536 | */ | |
537 | static void | |
538 | bfa_iocfc_disable_cbfn(void *bfa_arg) | |
539 | { | |
540 | struct bfa_s *bfa = bfa_arg; | |
541 | ||
542 | bfa_isr_disable(bfa); | |
543 | bfa_iocfc_disable_submod(bfa); | |
544 | ||
545 | if (bfa->iocfc.action == BFA_IOCFC_ACT_STOP) | |
546 | bfa_cb_queue(bfa, &bfa->iocfc.stop_hcb_qe, bfa_iocfc_stop_cb, | |
547 | bfa); | |
548 | else { | |
549 | bfa_assert(bfa->iocfc.action == BFA_IOCFC_ACT_DISABLE); | |
550 | bfa_cb_queue(bfa, &bfa->iocfc.dis_hcb_qe, bfa_iocfc_disable_cb, | |
551 | bfa); | |
552 | } | |
553 | } | |
554 | ||
555 | /** | |
556 | * Notify sub-modules of hardware failure. | |
557 | */ | |
558 | static void | |
559 | bfa_iocfc_hbfail_cbfn(void *bfa_arg) | |
560 | { | |
561 | struct bfa_s *bfa = bfa_arg; | |
562 | ||
563 | bfa->rme_process = BFA_FALSE; | |
564 | ||
565 | bfa_isr_disable(bfa); | |
566 | bfa_iocfc_disable_submod(bfa); | |
567 | ||
568 | if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT) | |
569 | bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe, bfa_iocfc_init_cb, | |
570 | bfa); | |
571 | } | |
572 | ||
573 | /** | |
574 | * Actions on chip-reset completion. | |
575 | */ | |
576 | static void | |
577 | bfa_iocfc_reset_cbfn(void *bfa_arg) | |
578 | { | |
579 | struct bfa_s *bfa = bfa_arg; | |
580 | ||
581 | bfa_iocfc_reset_queues(bfa); | |
582 | bfa_isr_enable(bfa); | |
583 | } | |
584 | ||
585 | ||
586 | ||
587 | /** | |
588 | * bfa_ioc_public | |
589 | */ | |
590 | ||
591 | /** | |
592 | * Query IOC memory requirement information. | |
593 | */ | |
594 | void | |
595 | bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, | |
596 | u32 *dm_len) | |
597 | { | |
598 | /* dma memory for IOC */ | |
599 | *dm_len += bfa_ioc_meminfo(); | |
600 | ||
601 | bfa_iocfc_fw_cfg_sz(cfg, dm_len); | |
602 | bfa_iocfc_cqs_sz(cfg, dm_len); | |
603 | *km_len += bfa_ioc_debug_trcsz(bfa_auto_recover); | |
604 | } | |
605 | ||
606 | /** | |
607 | * Query IOC memory requirement information. | |
608 | */ | |
609 | void | |
610 | bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, | |
611 | struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) | |
612 | { | |
613 | int i; | |
614 | ||
615 | bfa_iocfc_cbfn.enable_cbfn = bfa_iocfc_enable_cbfn; | |
616 | bfa_iocfc_cbfn.disable_cbfn = bfa_iocfc_disable_cbfn; | |
617 | bfa_iocfc_cbfn.hbfail_cbfn = bfa_iocfc_hbfail_cbfn; | |
618 | bfa_iocfc_cbfn.reset_cbfn = bfa_iocfc_reset_cbfn; | |
619 | ||
620 | bfa_ioc_attach(&bfa->ioc, bfa, &bfa_iocfc_cbfn, &bfa->timer_mod, | |
621 | bfa->trcmod, bfa->aen, bfa->logm); | |
622 | bfa_ioc_pci_init(&bfa->ioc, pcidev, BFI_MC_IOCFC); | |
623 | bfa_ioc_mbox_register(&bfa->ioc, bfa_mbox_isrs); | |
624 | ||
625 | /** | |
626 | * Choose FC (ssid: 0x1C) v/s FCoE (ssid: 0x14) mode. | |
627 | */ | |
628 | if (0) | |
629 | bfa_ioc_set_fcmode(&bfa->ioc); | |
630 | ||
631 | bfa_iocfc_init_mem(bfa, bfad, cfg, pcidev); | |
632 | bfa_iocfc_mem_claim(bfa, cfg, meminfo); | |
633 | bfa_timer_init(&bfa->timer_mod); | |
634 | ||
635 | INIT_LIST_HEAD(&bfa->comp_q); | |
636 | for (i = 0; i < BFI_IOC_MAX_CQS; i++) | |
637 | INIT_LIST_HEAD(&bfa->reqq_waitq[i]); | |
638 | } | |
639 | ||
640 | /** | |
641 | * Query IOC memory requirement information. | |
642 | */ | |
643 | void | |
644 | bfa_iocfc_detach(struct bfa_s *bfa) | |
645 | { | |
646 | bfa_ioc_detach(&bfa->ioc); | |
647 | } | |
648 | ||
649 | /** | |
650 | * Query IOC memory requirement information. | |
651 | */ | |
652 | void | |
653 | bfa_iocfc_init(struct bfa_s *bfa) | |
654 | { | |
655 | bfa->iocfc.action = BFA_IOCFC_ACT_INIT; | |
656 | bfa_ioc_enable(&bfa->ioc); | |
657 | bfa_msix_install(bfa); | |
658 | } | |
659 | ||
660 | /** | |
661 | * IOC start called from bfa_start(). Called to start IOC operations | |
662 | * at driver instantiation for this instance. | |
663 | */ | |
664 | void | |
665 | bfa_iocfc_start(struct bfa_s *bfa) | |
666 | { | |
667 | if (bfa->iocfc.cfgdone) | |
668 | bfa_iocfc_start_submod(bfa); | |
669 | } | |
670 | ||
671 | /** | |
672 | * IOC stop called from bfa_stop(). Called only when driver is unloaded | |
673 | * for this instance. | |
674 | */ | |
675 | void | |
676 | bfa_iocfc_stop(struct bfa_s *bfa) | |
677 | { | |
678 | bfa->iocfc.action = BFA_IOCFC_ACT_STOP; | |
679 | ||
680 | bfa->rme_process = BFA_FALSE; | |
681 | bfa_ioc_disable(&bfa->ioc); | |
682 | } | |
683 | ||
684 | void | |
685 | bfa_iocfc_isr(void *bfaarg, struct bfi_mbmsg_s *m) | |
686 | { | |
687 | struct bfa_s *bfa = bfaarg; | |
688 | struct bfa_iocfc_s *iocfc = &bfa->iocfc; | |
689 | union bfi_iocfc_i2h_msg_u *msg; | |
690 | ||
691 | msg = (union bfi_iocfc_i2h_msg_u *) m; | |
692 | bfa_trc(bfa, msg->mh.msg_id); | |
693 | ||
694 | switch (msg->mh.msg_id) { | |
695 | case BFI_IOCFC_I2H_CFG_REPLY: | |
696 | iocfc->cfg_reply = &msg->cfg_reply; | |
697 | bfa_iocfc_cfgrsp(bfa); | |
698 | break; | |
699 | ||
700 | case BFI_IOCFC_I2H_GET_STATS_RSP: | |
701 | if (iocfc->stats_busy == BFA_FALSE | |
702 | || iocfc->stats_status == BFA_STATUS_ETIMER) | |
703 | break; | |
704 | ||
705 | bfa_timer_stop(&iocfc->stats_timer); | |
706 | iocfc->stats_status = BFA_STATUS_OK; | |
707 | bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_cb, | |
708 | bfa); | |
709 | break; | |
710 | case BFI_IOCFC_I2H_CLEAR_STATS_RSP: | |
711 | /* | |
712 | * check for timer pop before processing the rsp | |
713 | */ | |
714 | if (iocfc->stats_busy == BFA_FALSE | |
715 | || iocfc->stats_status == BFA_STATUS_ETIMER) | |
716 | break; | |
717 | ||
718 | bfa_timer_stop(&iocfc->stats_timer); | |
719 | iocfc->stats_status = BFA_STATUS_OK; | |
720 | bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, | |
721 | bfa_iocfc_stats_clr_cb, bfa); | |
722 | break; | |
723 | case BFI_IOCFC_I2H_UPDATEQ_RSP: | |
724 | iocfc->updateq_cbfn(iocfc->updateq_cbarg, BFA_STATUS_OK); | |
725 | break; | |
726 | default: | |
727 | bfa_assert(0); | |
728 | } | |
729 | } | |
730 | ||
731 | #ifndef BFA_BIOS_BUILD | |
732 | void | |
733 | bfa_adapter_get_attr(struct bfa_s *bfa, struct bfa_adapter_attr_s *ad_attr) | |
734 | { | |
735 | bfa_ioc_get_adapter_attr(&bfa->ioc, ad_attr); | |
736 | } | |
737 | ||
738 | u64 | |
739 | bfa_adapter_get_id(struct bfa_s *bfa) | |
740 | { | |
741 | return bfa_ioc_get_adid(&bfa->ioc); | |
742 | } | |
743 | ||
744 | void | |
745 | bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr) | |
746 | { | |
747 | struct bfa_iocfc_s *iocfc = &bfa->iocfc; | |
748 | ||
749 | attr->intr_attr = iocfc->cfginfo->intr_attr; | |
750 | attr->config = iocfc->cfg; | |
751 | } | |
752 | ||
753 | bfa_status_t | |
754 | bfa_iocfc_israttr_set(struct bfa_s *bfa, struct bfa_iocfc_intr_attr_s *attr) | |
755 | { | |
756 | struct bfa_iocfc_s *iocfc = &bfa->iocfc; | |
757 | struct bfi_iocfc_set_intr_req_s *m; | |
758 | ||
759 | iocfc->cfginfo->intr_attr = *attr; | |
760 | if (!bfa_iocfc_is_operational(bfa)) | |
761 | return BFA_STATUS_OK; | |
762 | ||
763 | m = bfa_reqq_next(bfa, BFA_REQQ_IOC); | |
764 | if (!m) | |
765 | return BFA_STATUS_DEVBUSY; | |
766 | ||
767 | bfi_h2i_set(m->mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_SET_INTR_REQ, | |
768 | bfa_lpuid(bfa)); | |
769 | m->coalesce = attr->coalesce; | |
770 | m->delay = bfa_os_htons(attr->delay); | |
771 | m->latency = bfa_os_htons(attr->latency); | |
772 | ||
773 | bfa_trc(bfa, attr->delay); | |
774 | bfa_trc(bfa, attr->latency); | |
775 | ||
776 | bfa_reqq_produce(bfa, BFA_REQQ_IOC); | |
777 | return BFA_STATUS_OK; | |
778 | } | |
779 | ||
780 | void | |
781 | bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa) | |
782 | { | |
783 | struct bfa_iocfc_s *iocfc = &bfa->iocfc; | |
784 | ||
785 | iocfc->cfginfo->sense_buf_len = (BFI_IOIM_SNSLEN - 1); | |
786 | bfa_dma_be_addr_set(iocfc->cfginfo->ioim_snsbase, snsbase_pa); | |
787 | } | |
788 | ||
789 | bfa_status_t | |
790 | bfa_iocfc_get_stats(struct bfa_s *bfa, struct bfa_iocfc_stats_s *stats, | |
791 | bfa_cb_ioc_t cbfn, void *cbarg) | |
792 | { | |
793 | struct bfa_iocfc_s *iocfc = &bfa->iocfc; | |
794 | ||
795 | if (iocfc->stats_busy) { | |
796 | bfa_trc(bfa, iocfc->stats_busy); | |
f8ceafde | 797 | return BFA_STATUS_DEVBUSY; |
7725ccfd JH |
798 | } |
799 | ||
800 | iocfc->stats_busy = BFA_TRUE; | |
801 | iocfc->stats_ret = stats; | |
802 | iocfc->stats_cbfn = cbfn; | |
803 | iocfc->stats_cbarg = cbarg; | |
804 | ||
805 | bfa_iocfc_stats_query(bfa); | |
806 | ||
f8ceafde | 807 | return BFA_STATUS_OK; |
7725ccfd JH |
808 | } |
809 | ||
810 | bfa_status_t | |
811 | bfa_iocfc_clear_stats(struct bfa_s *bfa, bfa_cb_ioc_t cbfn, void *cbarg) | |
812 | { | |
813 | struct bfa_iocfc_s *iocfc = &bfa->iocfc; | |
814 | ||
815 | if (iocfc->stats_busy) { | |
816 | bfa_trc(bfa, iocfc->stats_busy); | |
f8ceafde | 817 | return BFA_STATUS_DEVBUSY; |
7725ccfd JH |
818 | } |
819 | ||
820 | iocfc->stats_busy = BFA_TRUE; | |
821 | iocfc->stats_cbfn = cbfn; | |
822 | iocfc->stats_cbarg = cbarg; | |
823 | ||
824 | bfa_iocfc_stats_clear(bfa); | |
f8ceafde | 825 | return BFA_STATUS_OK; |
7725ccfd JH |
826 | } |
827 | ||
828 | /** | |
829 | * Enable IOC after it is disabled. | |
830 | */ | |
831 | void | |
832 | bfa_iocfc_enable(struct bfa_s *bfa) | |
833 | { | |
834 | bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0, | |
835 | "IOC Enable"); | |
836 | bfa_ioc_enable(&bfa->ioc); | |
837 | } | |
838 | ||
839 | void | |
840 | bfa_iocfc_disable(struct bfa_s *bfa) | |
841 | { | |
842 | bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0, | |
843 | "IOC Disable"); | |
844 | bfa->iocfc.action = BFA_IOCFC_ACT_DISABLE; | |
845 | ||
846 | bfa->rme_process = BFA_FALSE; | |
847 | bfa_ioc_disable(&bfa->ioc); | |
848 | } | |
849 | ||
850 | ||
851 | bfa_boolean_t | |
852 | bfa_iocfc_is_operational(struct bfa_s *bfa) | |
853 | { | |
854 | return bfa_ioc_is_operational(&bfa->ioc) && bfa->iocfc.cfgdone; | |
855 | } | |
856 | ||
857 | /** | |
858 | * Return boot target port wwns -- read from boot information in flash. | |
859 | */ | |
860 | void | |
861 | bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t **wwns) | |
862 | { | |
863 | struct bfa_iocfc_s *iocfc = &bfa->iocfc; | |
864 | struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; | |
865 | ||
866 | *nwwns = cfgrsp->bootwwns.nwwns; | |
867 | *wwns = cfgrsp->bootwwns.wwn; | |
868 | } | |
869 | ||
870 | #endif | |
871 | ||
872 |