diff options
Diffstat (limited to 'drivers/scsi/bfa/bfa_iocfc.c')
-rw-r--r-- | drivers/scsi/bfa/bfa_iocfc.c | 872 |
1 files changed, 872 insertions, 0 deletions
diff --git a/drivers/scsi/bfa/bfa_iocfc.c b/drivers/scsi/bfa/bfa_iocfc.c new file mode 100644 index 000000000000..12350b022d63 --- /dev/null +++ b/drivers/scsi/bfa/bfa_iocfc.c | |||
@@ -0,0 +1,872 @@ | |||
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); | ||
797 | return (BFA_STATUS_DEVBUSY); | ||
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 | |||
807 | return (BFA_STATUS_OK); | ||
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); | ||
817 | return (BFA_STATUS_DEVBUSY); | ||
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); | ||
825 | return (BFA_STATUS_OK); | ||
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 | |||