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 | /** | |
19 | * bfad.c Linux driver PCI interface module. | |
20 | */ | |
21 | ||
5a0e3ad6 | 22 | #include <linux/slab.h> |
7725ccfd | 23 | #include <linux/module.h> |
e6714324 | 24 | #include <linux/kthread.h> |
7725ccfd JH |
25 | #include "bfad_drv.h" |
26 | #include "bfad_im.h" | |
27 | #include "bfad_tm.h" | |
28 | #include "bfad_ipfc.h" | |
29 | #include "bfad_trcmod.h" | |
30 | #include <fcb/bfa_fcb_vf.h> | |
31 | #include <fcb/bfa_fcb_rport.h> | |
32 | #include <fcb/bfa_fcb_port.h> | |
33 | #include <fcb/bfa_fcb.h> | |
34 | ||
35 | BFA_TRC_FILE(LDRV, BFAD); | |
42b426ec | 36 | DEFINE_MUTEX(bfad_mutex); |
7725ccfd JH |
37 | LIST_HEAD(bfad_list); |
38 | static int bfad_inst; | |
39 | int bfad_supported_fc4s; | |
40 | ||
41 | static char *host_name; | |
42 | static char *os_name; | |
43 | static char *os_patch; | |
44 | static int num_rports; | |
45 | static int num_ios; | |
46 | static int num_tms; | |
47 | static int num_fcxps; | |
48 | static int num_ufbufs; | |
49 | static int reqq_size; | |
50 | static int rspq_size; | |
51 | static int num_sgpgs; | |
52 | static int rport_del_timeout = BFA_FCS_RPORT_DEF_DEL_TIMEOUT; | |
53 | static int bfa_io_max_sge = BFAD_IO_MAX_SGE; | |
54 | static int log_level = BFA_LOG_WARNING; | |
55 | static int ioc_auto_recover = BFA_TRUE; | |
56 | static int ipfc_enable = BFA_FALSE; | |
57 | static int ipfc_mtu = -1; | |
5b098082 | 58 | static int fdmi_enable = BFA_TRUE; |
7725ccfd JH |
59 | int bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH; |
60 | int bfa_linkup_delay = -1; | |
61 | ||
62 | module_param(os_name, charp, S_IRUGO | S_IWUSR); | |
63 | module_param(os_patch, charp, S_IRUGO | S_IWUSR); | |
64 | module_param(host_name, charp, S_IRUGO | S_IWUSR); | |
65 | module_param(num_rports, int, S_IRUGO | S_IWUSR); | |
66 | module_param(num_ios, int, S_IRUGO | S_IWUSR); | |
67 | module_param(num_tms, int, S_IRUGO | S_IWUSR); | |
68 | module_param(num_fcxps, int, S_IRUGO | S_IWUSR); | |
69 | module_param(num_ufbufs, int, S_IRUGO | S_IWUSR); | |
70 | module_param(reqq_size, int, S_IRUGO | S_IWUSR); | |
71 | module_param(rspq_size, int, S_IRUGO | S_IWUSR); | |
72 | module_param(num_sgpgs, int, S_IRUGO | S_IWUSR); | |
73 | module_param(rport_del_timeout, int, S_IRUGO | S_IWUSR); | |
74 | module_param(bfa_lun_queue_depth, int, S_IRUGO | S_IWUSR); | |
75 | module_param(bfa_io_max_sge, int, S_IRUGO | S_IWUSR); | |
76 | module_param(log_level, int, S_IRUGO | S_IWUSR); | |
77 | module_param(ioc_auto_recover, int, S_IRUGO | S_IWUSR); | |
78 | module_param(ipfc_enable, int, S_IRUGO | S_IWUSR); | |
79 | module_param(ipfc_mtu, int, S_IRUGO | S_IWUSR); | |
5b098082 | 80 | module_param(fdmi_enable, int, S_IRUGO | S_IWUSR); |
7725ccfd JH |
81 | module_param(bfa_linkup_delay, int, S_IRUGO | S_IWUSR); |
82 | ||
83 | /* | |
84 | * Stores the module parm num_sgpgs value; | |
85 | * used to reset for bfad next instance. | |
86 | */ | |
87 | static int num_sgpgs_parm; | |
88 | ||
89 | static bfa_status_t | |
90 | bfad_fc4_probe(struct bfad_s *bfad) | |
91 | { | |
92 | int rc; | |
93 | ||
94 | rc = bfad_im_probe(bfad); | |
95 | if (rc != BFA_STATUS_OK) | |
96 | goto ext; | |
97 | ||
98 | bfad_tm_probe(bfad); | |
99 | ||
100 | if (ipfc_enable) | |
101 | bfad_ipfc_probe(bfad); | |
e6714324 KG |
102 | |
103 | bfad->bfad_flags |= BFAD_FC4_PROBE_DONE; | |
7725ccfd JH |
104 | ext: |
105 | return rc; | |
106 | } | |
107 | ||
108 | static void | |
109 | bfad_fc4_probe_undo(struct bfad_s *bfad) | |
110 | { | |
111 | bfad_im_probe_undo(bfad); | |
112 | bfad_tm_probe_undo(bfad); | |
113 | if (ipfc_enable) | |
114 | bfad_ipfc_probe_undo(bfad); | |
e6714324 | 115 | bfad->bfad_flags &= ~BFAD_FC4_PROBE_DONE; |
7725ccfd JH |
116 | } |
117 | ||
118 | static void | |
119 | bfad_fc4_probe_post(struct bfad_s *bfad) | |
120 | { | |
121 | if (bfad->im) | |
122 | bfad_im_probe_post(bfad->im); | |
123 | ||
124 | bfad_tm_probe_post(bfad); | |
125 | if (ipfc_enable) | |
126 | bfad_ipfc_probe_post(bfad); | |
127 | } | |
128 | ||
129 | static bfa_status_t | |
130 | bfad_fc4_port_new(struct bfad_s *bfad, struct bfad_port_s *port, int roles) | |
131 | { | |
132 | int rc = BFA_STATUS_FAILED; | |
133 | ||
134 | if (roles & BFA_PORT_ROLE_FCP_IM) | |
135 | rc = bfad_im_port_new(bfad, port); | |
136 | if (rc != BFA_STATUS_OK) | |
137 | goto ext; | |
138 | ||
139 | if (roles & BFA_PORT_ROLE_FCP_TM) | |
140 | rc = bfad_tm_port_new(bfad, port); | |
141 | if (rc != BFA_STATUS_OK) | |
142 | goto ext; | |
143 | ||
144 | if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) | |
145 | rc = bfad_ipfc_port_new(bfad, port, port->pvb_type); | |
146 | ext: | |
147 | return rc; | |
148 | } | |
149 | ||
150 | static void | |
151 | bfad_fc4_port_delete(struct bfad_s *bfad, struct bfad_port_s *port, int roles) | |
152 | { | |
153 | if (roles & BFA_PORT_ROLE_FCP_IM) | |
154 | bfad_im_port_delete(bfad, port); | |
155 | ||
156 | if (roles & BFA_PORT_ROLE_FCP_TM) | |
157 | bfad_tm_port_delete(bfad, port); | |
158 | ||
159 | if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) | |
160 | bfad_ipfc_port_delete(bfad, port); | |
161 | } | |
162 | ||
163 | /** | |
164 | * BFA callbacks | |
165 | */ | |
166 | void | |
167 | bfad_hcb_comp(void *arg, bfa_status_t status) | |
168 | { | |
169 | struct bfad_hal_comp *fcomp = (struct bfad_hal_comp *)arg; | |
170 | ||
171 | fcomp->status = status; | |
172 | complete(&fcomp->comp); | |
173 | } | |
174 | ||
175 | /** | |
176 | * bfa_init callback | |
177 | */ | |
178 | void | |
179 | bfa_cb_init(void *drv, bfa_status_t init_status) | |
180 | { | |
181 | struct bfad_s *bfad = drv; | |
182 | ||
e6714324 | 183 | if (init_status == BFA_STATUS_OK) { |
7725ccfd JH |
184 | bfad->bfad_flags |= BFAD_HAL_INIT_DONE; |
185 | ||
e6714324 KG |
186 | /* If BFAD_HAL_INIT_FAIL flag is set: |
187 | * Wake up the kernel thread to start | |
188 | * the bfad operations after HAL init done | |
189 | */ | |
190 | if ((bfad->bfad_flags & BFAD_HAL_INIT_FAIL)) { | |
191 | bfad->bfad_flags &= ~BFAD_HAL_INIT_FAIL; | |
192 | wake_up_process(bfad->bfad_tsk); | |
193 | } | |
194 | } | |
195 | ||
7725ccfd JH |
196 | complete(&bfad->comp); |
197 | } | |
198 | ||
199 | ||
200 | ||
201 | /** | |
202 | * BFA_FCS callbacks | |
203 | */ | |
204 | static struct bfad_port_s * | |
205 | bfad_get_drv_port(struct bfad_s *bfad, struct bfad_vf_s *vf_drv, | |
206 | struct bfad_vport_s *vp_drv) | |
207 | { | |
f8ceafde JH |
208 | return (vp_drv) ? (&(vp_drv)->drv_port) |
209 | : ((vf_drv) ? (&(vf_drv)->base_port) : (&(bfad)->pport)); | |
7725ccfd JH |
210 | } |
211 | ||
212 | struct bfad_port_s * | |
213 | bfa_fcb_port_new(struct bfad_s *bfad, struct bfa_fcs_port_s *port, | |
214 | enum bfa_port_role roles, struct bfad_vf_s *vf_drv, | |
215 | struct bfad_vport_s *vp_drv) | |
216 | { | |
217 | bfa_status_t rc; | |
218 | struct bfad_port_s *port_drv; | |
219 | ||
220 | if (!vp_drv && !vf_drv) { | |
221 | port_drv = &bfad->pport; | |
222 | port_drv->pvb_type = BFAD_PORT_PHYS_BASE; | |
223 | } else if (!vp_drv && vf_drv) { | |
224 | port_drv = &vf_drv->base_port; | |
225 | port_drv->pvb_type = BFAD_PORT_VF_BASE; | |
226 | } else if (vp_drv && !vf_drv) { | |
227 | port_drv = &vp_drv->drv_port; | |
228 | port_drv->pvb_type = BFAD_PORT_PHYS_VPORT; | |
229 | } else { | |
230 | port_drv = &vp_drv->drv_port; | |
231 | port_drv->pvb_type = BFAD_PORT_VF_VPORT; | |
232 | } | |
233 | ||
234 | port_drv->fcs_port = port; | |
235 | port_drv->roles = roles; | |
236 | rc = bfad_fc4_port_new(bfad, port_drv, roles); | |
237 | if (rc != BFA_STATUS_OK) { | |
238 | bfad_fc4_port_delete(bfad, port_drv, roles); | |
239 | port_drv = NULL; | |
240 | } | |
241 | ||
242 | return port_drv; | |
243 | } | |
244 | ||
245 | void | |
246 | bfa_fcb_port_delete(struct bfad_s *bfad, enum bfa_port_role roles, | |
247 | struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv) | |
248 | { | |
249 | struct bfad_port_s *port_drv; | |
250 | ||
251 | /* | |
252 | * this will be only called from rmmod context | |
253 | */ | |
254 | if (vp_drv && !vp_drv->comp_del) { | |
255 | port_drv = bfad_get_drv_port(bfad, vf_drv, vp_drv); | |
256 | bfa_trc(bfad, roles); | |
257 | bfad_fc4_port_delete(bfad, port_drv, roles); | |
258 | } | |
259 | } | |
260 | ||
261 | void | |
262 | bfa_fcb_port_online(struct bfad_s *bfad, enum bfa_port_role roles, | |
263 | struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv) | |
264 | { | |
265 | struct bfad_port_s *port_drv = bfad_get_drv_port(bfad, vf_drv, vp_drv); | |
266 | ||
267 | if (roles & BFA_PORT_ROLE_FCP_IM) | |
268 | bfad_im_port_online(bfad, port_drv); | |
269 | ||
270 | if (roles & BFA_PORT_ROLE_FCP_TM) | |
271 | bfad_tm_port_online(bfad, port_drv); | |
272 | ||
273 | if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) | |
274 | bfad_ipfc_port_online(bfad, port_drv); | |
275 | ||
276 | bfad->bfad_flags |= BFAD_PORT_ONLINE; | |
277 | } | |
278 | ||
279 | void | |
280 | bfa_fcb_port_offline(struct bfad_s *bfad, enum bfa_port_role roles, | |
281 | struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv) | |
282 | { | |
283 | struct bfad_port_s *port_drv = bfad_get_drv_port(bfad, vf_drv, vp_drv); | |
284 | ||
285 | if (roles & BFA_PORT_ROLE_FCP_IM) | |
286 | bfad_im_port_offline(bfad, port_drv); | |
287 | ||
288 | if (roles & BFA_PORT_ROLE_FCP_TM) | |
289 | bfad_tm_port_offline(bfad, port_drv); | |
290 | ||
291 | if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) | |
292 | bfad_ipfc_port_offline(bfad, port_drv); | |
293 | } | |
294 | ||
295 | void | |
296 | bfa_fcb_vport_delete(struct bfad_vport_s *vport_drv) | |
297 | { | |
298 | if (vport_drv->comp_del) { | |
299 | complete(vport_drv->comp_del); | |
300 | return; | |
301 | } | |
7725ccfd JH |
302 | } |
303 | ||
304 | /** | |
305 | * FCS RPORT alloc callback, after successful PLOGI by FCS | |
306 | */ | |
307 | bfa_status_t | |
308 | bfa_fcb_rport_alloc(struct bfad_s *bfad, struct bfa_fcs_rport_s **rport, | |
309 | struct bfad_rport_s **rport_drv) | |
310 | { | |
311 | bfa_status_t rc = BFA_STATUS_OK; | |
312 | ||
313 | *rport_drv = kzalloc(sizeof(struct bfad_rport_s), GFP_ATOMIC); | |
314 | if (*rport_drv == NULL) { | |
315 | rc = BFA_STATUS_ENOMEM; | |
316 | goto ext; | |
317 | } | |
318 | ||
319 | *rport = &(*rport_drv)->fcs_rport; | |
320 | ||
321 | ext: | |
322 | return rc; | |
323 | } | |
324 | ||
d9883548 JH |
325 | /** |
326 | * @brief | |
327 | * FCS PBC VPORT Create | |
328 | */ | |
329 | void | |
330 | bfa_fcb_pbc_vport_create(struct bfad_s *bfad, struct bfi_pbc_vport_s pbc_vport) | |
331 | { | |
332 | ||
333 | struct bfad_pcfg_s *pcfg; | |
334 | ||
335 | pcfg = kzalloc(sizeof(struct bfad_pcfg_s), GFP_ATOMIC); | |
336 | if (!pcfg) { | |
337 | bfa_trc(bfad, 0); | |
338 | return; | |
339 | } | |
7725ccfd | 340 | |
d9883548 JH |
341 | pcfg->port_cfg.roles = BFA_PORT_ROLE_FCP_IM; |
342 | pcfg->port_cfg.pwwn = pbc_vport.vp_pwwn; | |
343 | pcfg->port_cfg.nwwn = pbc_vport.vp_nwwn; | |
344 | pcfg->port_cfg.preboot_vp = BFA_TRUE; | |
345 | ||
346 | list_add_tail(&pcfg->list_entry, &bfad->pbc_pcfg_list); | |
347 | ||
348 | return; | |
349 | } | |
7725ccfd JH |
350 | |
351 | void | |
352 | bfad_hal_mem_release(struct bfad_s *bfad) | |
353 | { | |
354 | int i; | |
355 | struct bfa_meminfo_s *hal_meminfo = &bfad->meminfo; | |
356 | struct bfa_mem_elem_s *meminfo_elem; | |
357 | ||
358 | for (i = 0; i < BFA_MEM_TYPE_MAX; i++) { | |
359 | meminfo_elem = &hal_meminfo->meminfo[i]; | |
360 | if (meminfo_elem->kva != NULL) { | |
361 | switch (meminfo_elem->mem_type) { | |
362 | case BFA_MEM_TYPE_KVA: | |
363 | vfree(meminfo_elem->kva); | |
364 | break; | |
365 | case BFA_MEM_TYPE_DMA: | |
366 | dma_free_coherent(&bfad->pcidev->dev, | |
367 | meminfo_elem->mem_len, | |
368 | meminfo_elem->kva, | |
369 | (dma_addr_t) meminfo_elem->dma); | |
370 | break; | |
371 | default: | |
372 | bfa_assert(0); | |
373 | break; | |
374 | } | |
375 | } | |
376 | } | |
377 | ||
378 | memset(hal_meminfo, 0, sizeof(struct bfa_meminfo_s)); | |
379 | } | |
380 | ||
381 | void | |
382 | bfad_update_hal_cfg(struct bfa_iocfc_cfg_s *bfa_cfg) | |
383 | { | |
384 | if (num_rports > 0) | |
385 | bfa_cfg->fwcfg.num_rports = num_rports; | |
386 | if (num_ios > 0) | |
387 | bfa_cfg->fwcfg.num_ioim_reqs = num_ios; | |
388 | if (num_tms > 0) | |
389 | bfa_cfg->fwcfg.num_tskim_reqs = num_tms; | |
390 | if (num_fcxps > 0) | |
391 | bfa_cfg->fwcfg.num_fcxp_reqs = num_fcxps; | |
392 | if (num_ufbufs > 0) | |
393 | bfa_cfg->fwcfg.num_uf_bufs = num_ufbufs; | |
394 | if (reqq_size > 0) | |
395 | bfa_cfg->drvcfg.num_reqq_elems = reqq_size; | |
396 | if (rspq_size > 0) | |
397 | bfa_cfg->drvcfg.num_rspq_elems = rspq_size; | |
398 | if (num_sgpgs > 0) | |
399 | bfa_cfg->drvcfg.num_sgpgs = num_sgpgs; | |
400 | ||
401 | /* | |
402 | * populate the hal values back to the driver for sysfs use. | |
403 | * otherwise, the default values will be shown as 0 in sysfs | |
404 | */ | |
405 | num_rports = bfa_cfg->fwcfg.num_rports; | |
406 | num_ios = bfa_cfg->fwcfg.num_ioim_reqs; | |
407 | num_tms = bfa_cfg->fwcfg.num_tskim_reqs; | |
408 | num_fcxps = bfa_cfg->fwcfg.num_fcxp_reqs; | |
409 | num_ufbufs = bfa_cfg->fwcfg.num_uf_bufs; | |
410 | reqq_size = bfa_cfg->drvcfg.num_reqq_elems; | |
411 | rspq_size = bfa_cfg->drvcfg.num_rspq_elems; | |
412 | num_sgpgs = bfa_cfg->drvcfg.num_sgpgs; | |
413 | } | |
414 | ||
415 | bfa_status_t | |
416 | bfad_hal_mem_alloc(struct bfad_s *bfad) | |
417 | { | |
418 | struct bfa_meminfo_s *hal_meminfo = &bfad->meminfo; | |
419 | struct bfa_mem_elem_s *meminfo_elem; | |
420 | bfa_status_t rc = BFA_STATUS_OK; | |
421 | dma_addr_t phys_addr; | |
422 | int retry_count = 0; | |
423 | int reset_value = 1; | |
424 | int min_num_sgpgs = 512; | |
425 | void *kva; | |
426 | int i; | |
427 | ||
428 | bfa_cfg_get_default(&bfad->ioc_cfg); | |
429 | ||
430 | retry: | |
431 | bfad_update_hal_cfg(&bfad->ioc_cfg); | |
432 | bfad->cfg_data.ioc_queue_depth = bfad->ioc_cfg.fwcfg.num_ioim_reqs; | |
433 | bfa_cfg_get_meminfo(&bfad->ioc_cfg, hal_meminfo); | |
434 | ||
435 | for (i = 0; i < BFA_MEM_TYPE_MAX; i++) { | |
436 | meminfo_elem = &hal_meminfo->meminfo[i]; | |
437 | switch (meminfo_elem->mem_type) { | |
438 | case BFA_MEM_TYPE_KVA: | |
439 | kva = vmalloc(meminfo_elem->mem_len); | |
440 | if (kva == NULL) { | |
441 | bfad_hal_mem_release(bfad); | |
442 | rc = BFA_STATUS_ENOMEM; | |
443 | goto ext; | |
444 | } | |
445 | memset(kva, 0, meminfo_elem->mem_len); | |
446 | meminfo_elem->kva = kva; | |
447 | break; | |
448 | case BFA_MEM_TYPE_DMA: | |
449 | kva = dma_alloc_coherent(&bfad->pcidev->dev, | |
450 | meminfo_elem->mem_len, | |
451 | &phys_addr, GFP_KERNEL); | |
452 | if (kva == NULL) { | |
453 | bfad_hal_mem_release(bfad); | |
454 | /* | |
455 | * If we cannot allocate with default | |
456 | * num_sgpages try with half the value. | |
457 | */ | |
458 | if (num_sgpgs > min_num_sgpgs) { | |
459 | printk(KERN_INFO "bfad[%d]: memory" | |
460 | " allocation failed with" | |
461 | " num_sgpgs: %d\n", | |
462 | bfad->inst_no, num_sgpgs); | |
463 | nextLowerInt(&num_sgpgs); | |
464 | printk(KERN_INFO "bfad[%d]: trying to" | |
465 | " allocate memory with" | |
466 | " num_sgpgs: %d\n", | |
467 | bfad->inst_no, num_sgpgs); | |
468 | retry_count++; | |
469 | goto retry; | |
470 | } else { | |
471 | if (num_sgpgs_parm > 0) | |
472 | num_sgpgs = num_sgpgs_parm; | |
473 | else { | |
474 | reset_value = | |
475 | (1 << retry_count); | |
476 | num_sgpgs *= reset_value; | |
477 | } | |
478 | rc = BFA_STATUS_ENOMEM; | |
479 | goto ext; | |
480 | } | |
481 | } | |
482 | ||
483 | if (num_sgpgs_parm > 0) | |
484 | num_sgpgs = num_sgpgs_parm; | |
485 | else { | |
486 | reset_value = (1 << retry_count); | |
487 | num_sgpgs *= reset_value; | |
488 | } | |
489 | ||
490 | memset(kva, 0, meminfo_elem->mem_len); | |
491 | meminfo_elem->kva = kva; | |
492 | meminfo_elem->dma = phys_addr; | |
493 | break; | |
494 | default: | |
495 | break; | |
496 | ||
497 | } | |
498 | } | |
499 | ext: | |
500 | return rc; | |
501 | } | |
502 | ||
503 | /** | |
504 | * Create a vport under a vf. | |
505 | */ | |
506 | bfa_status_t | |
507 | bfad_vport_create(struct bfad_s *bfad, u16 vf_id, | |
d9883548 | 508 | struct bfa_port_cfg_s *port_cfg, struct device *dev) |
7725ccfd JH |
509 | { |
510 | struct bfad_vport_s *vport; | |
d9883548 | 511 | int rc = BFA_STATUS_OK; |
7725ccfd JH |
512 | unsigned long flags; |
513 | struct completion fcomp; | |
514 | ||
515 | vport = kzalloc(sizeof(struct bfad_vport_s), GFP_KERNEL); | |
516 | if (!vport) { | |
517 | rc = BFA_STATUS_ENOMEM; | |
518 | goto ext; | |
519 | } | |
520 | ||
521 | vport->drv_port.bfad = bfad; | |
522 | spin_lock_irqsave(&bfad->bfad_lock, flags); | |
d9883548 JH |
523 | if (port_cfg->preboot_vp == BFA_TRUE) |
524 | rc = bfa_fcs_pbc_vport_create(&vport->fcs_vport, | |
525 | &bfad->bfa_fcs, vf_id, port_cfg, vport); | |
526 | else | |
527 | rc = bfa_fcs_vport_create(&vport->fcs_vport, | |
528 | &bfad->bfa_fcs, vf_id, port_cfg, vport); | |
7725ccfd JH |
529 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); |
530 | ||
531 | if (rc != BFA_STATUS_OK) | |
532 | goto ext_free_vport; | |
533 | ||
534 | if (port_cfg->roles & BFA_PORT_ROLE_FCP_IM) { | |
b504293f JH |
535 | rc = bfad_im_scsi_host_alloc(bfad, vport->drv_port.im_port, |
536 | dev); | |
7725ccfd JH |
537 | if (rc != BFA_STATUS_OK) |
538 | goto ext_free_fcs_vport; | |
539 | } | |
540 | ||
541 | spin_lock_irqsave(&bfad->bfad_lock, flags); | |
542 | bfa_fcs_vport_start(&vport->fcs_vport); | |
543 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | |
544 | ||
545 | return BFA_STATUS_OK; | |
546 | ||
547 | ext_free_fcs_vport: | |
548 | spin_lock_irqsave(&bfad->bfad_lock, flags); | |
549 | vport->comp_del = &fcomp; | |
550 | init_completion(vport->comp_del); | |
551 | bfa_fcs_vport_delete(&vport->fcs_vport); | |
552 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | |
553 | wait_for_completion(vport->comp_del); | |
554 | ext_free_vport: | |
555 | kfree(vport); | |
556 | ext: | |
557 | return rc; | |
558 | } | |
559 | ||
560 | /** | |
561 | * Create a vf and its base vport implicitely. | |
562 | */ | |
563 | bfa_status_t | |
564 | bfad_vf_create(struct bfad_s *bfad, u16 vf_id, | |
565 | struct bfa_port_cfg_s *port_cfg) | |
566 | { | |
567 | struct bfad_vf_s *vf; | |
568 | int rc = BFA_STATUS_OK; | |
569 | ||
570 | vf = kzalloc(sizeof(struct bfad_vf_s), GFP_KERNEL); | |
571 | if (!vf) { | |
572 | rc = BFA_STATUS_FAILED; | |
573 | goto ext; | |
574 | } | |
575 | ||
576 | rc = bfa_fcs_vf_create(&vf->fcs_vf, &bfad->bfa_fcs, vf_id, port_cfg, | |
577 | vf); | |
578 | if (rc != BFA_STATUS_OK) | |
579 | kfree(vf); | |
580 | ext: | |
581 | return rc; | |
582 | } | |
583 | ||
584 | void | |
585 | bfad_bfa_tmo(unsigned long data) | |
586 | { | |
587 | struct bfad_s *bfad = (struct bfad_s *)data; | |
588 | unsigned long flags; | |
589 | struct list_head doneq; | |
590 | ||
591 | spin_lock_irqsave(&bfad->bfad_lock, flags); | |
592 | ||
593 | bfa_timer_tick(&bfad->bfa); | |
594 | ||
595 | bfa_comp_deq(&bfad->bfa, &doneq); | |
596 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | |
597 | ||
598 | if (!list_empty(&doneq)) { | |
599 | bfa_comp_process(&bfad->bfa, &doneq); | |
600 | spin_lock_irqsave(&bfad->bfad_lock, flags); | |
601 | bfa_comp_free(&bfad->bfa, &doneq); | |
602 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | |
603 | } | |
604 | ||
605 | mod_timer(&bfad->hal_tmo, jiffies + msecs_to_jiffies(BFA_TIMER_FREQ)); | |
606 | } | |
607 | ||
608 | void | |
609 | bfad_init_timer(struct bfad_s *bfad) | |
610 | { | |
611 | init_timer(&bfad->hal_tmo); | |
612 | bfad->hal_tmo.function = bfad_bfa_tmo; | |
613 | bfad->hal_tmo.data = (unsigned long)bfad; | |
614 | ||
615 | mod_timer(&bfad->hal_tmo, jiffies + msecs_to_jiffies(BFA_TIMER_FREQ)); | |
616 | } | |
617 | ||
618 | int | |
619 | bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad) | |
620 | { | |
7725ccfd JH |
621 | int rc = -ENODEV; |
622 | ||
623 | if (pci_enable_device(pdev)) { | |
624 | BFA_PRINTF(BFA_ERR, "pci_enable_device fail %p\n", pdev); | |
625 | goto out; | |
626 | } | |
627 | ||
628 | if (pci_request_regions(pdev, BFAD_DRIVER_NAME)) | |
629 | goto out_disable_device; | |
630 | ||
631 | pci_set_master(pdev); | |
632 | ||
633 | ||
634 | if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) | |
635 | if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) { | |
636 | BFA_PRINTF(BFA_ERR, "pci_set_dma_mask fail %p\n", pdev); | |
637 | goto out_release_region; | |
638 | } | |
639 | ||
b3522f08 | 640 | bfad->pci_bar0_kva = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); |
7725ccfd JH |
641 | |
642 | if (bfad->pci_bar0_kva == NULL) { | |
643 | BFA_PRINTF(BFA_ERR, "Fail to map bar0\n"); | |
644 | goto out_release_region; | |
645 | } | |
646 | ||
647 | bfad->hal_pcidev.pci_slot = PCI_SLOT(pdev->devfn); | |
648 | bfad->hal_pcidev.pci_func = PCI_FUNC(pdev->devfn); | |
649 | bfad->hal_pcidev.pci_bar_kva = bfad->pci_bar0_kva; | |
650 | bfad->hal_pcidev.device_id = pdev->device; | |
651 | bfad->pci_name = pci_name(pdev); | |
652 | ||
653 | bfad->pci_attr.vendor_id = pdev->vendor; | |
654 | bfad->pci_attr.device_id = pdev->device; | |
655 | bfad->pci_attr.ssid = pdev->subsystem_device; | |
656 | bfad->pci_attr.ssvid = pdev->subsystem_vendor; | |
657 | bfad->pci_attr.pcifn = PCI_FUNC(pdev->devfn); | |
658 | ||
659 | bfad->pcidev = pdev; | |
660 | return 0; | |
661 | ||
662 | out_release_region: | |
663 | pci_release_regions(pdev); | |
664 | out_disable_device: | |
665 | pci_disable_device(pdev); | |
666 | out: | |
667 | return rc; | |
668 | } | |
669 | ||
670 | void | |
671 | bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad) | |
672 | { | |
7725ccfd | 673 | pci_iounmap(pdev, bfad->pci_bar0_kva); |
7725ccfd JH |
674 | pci_release_regions(pdev); |
675 | pci_disable_device(pdev); | |
676 | pci_set_drvdata(pdev, NULL); | |
677 | } | |
678 | ||
679 | void | |
680 | bfad_fcs_port_cfg(struct bfad_s *bfad) | |
681 | { | |
682 | struct bfa_port_cfg_s port_cfg; | |
683 | struct bfa_pport_attr_s attr; | |
684 | char symname[BFA_SYMNAME_MAXLEN]; | |
685 | ||
686 | sprintf(symname, "%s-%d", BFAD_DRIVER_NAME, bfad->inst_no); | |
687 | memcpy(port_cfg.sym_name.symname, symname, strlen(symname)); | |
1c8a4c37 | 688 | bfa_fcport_get_attr(&bfad->bfa, &attr); |
7725ccfd JH |
689 | port_cfg.nwwn = attr.nwwn; |
690 | port_cfg.pwwn = attr.pwwn; | |
691 | ||
692 | bfa_fcs_cfg_base_port(&bfad->bfa_fcs, &port_cfg); | |
693 | } | |
694 | ||
695 | bfa_status_t | |
696 | bfad_drv_init(struct bfad_s *bfad) | |
697 | { | |
698 | bfa_status_t rc; | |
699 | unsigned long flags; | |
700 | struct bfa_fcs_driver_info_s driver_info; | |
7725ccfd JH |
701 | |
702 | bfad->cfg_data.rport_del_timeout = rport_del_timeout; | |
703 | bfad->cfg_data.lun_queue_depth = bfa_lun_queue_depth; | |
704 | bfad->cfg_data.io_max_sge = bfa_io_max_sge; | |
705 | bfad->cfg_data.binding_method = FCP_PWWN_BINDING; | |
706 | ||
707 | rc = bfad_hal_mem_alloc(bfad); | |
708 | if (rc != BFA_STATUS_OK) { | |
709 | printk(KERN_WARNING "bfad%d bfad_hal_mem_alloc failure\n", | |
710 | bfad->inst_no); | |
711 | printk(KERN_WARNING | |
712 | "Not enough memory to attach all Brocade HBA ports," | |
713 | " System may need more memory.\n"); | |
714 | goto out_hal_mem_alloc_failure; | |
715 | } | |
716 | ||
717 | bfa_init_log(&bfad->bfa, bfad->logmod); | |
718 | bfa_init_trc(&bfad->bfa, bfad->trcmod); | |
719 | bfa_init_aen(&bfad->bfa, bfad->aen); | |
2993cc71 | 720 | memset(bfad->file_map, 0, sizeof(bfad->file_map)); |
7725ccfd JH |
721 | bfa_init_plog(&bfad->bfa, &bfad->plog_buf); |
722 | bfa_plog_init(&bfad->plog_buf); | |
723 | bfa_plog_str(&bfad->plog_buf, BFA_PL_MID_DRVR, BFA_PL_EID_DRIVER_START, | |
724 | 0, "Driver Attach"); | |
725 | ||
726 | bfa_attach(&bfad->bfa, bfad, &bfad->ioc_cfg, &bfad->meminfo, | |
727 | &bfad->hal_pcidev); | |
728 | ||
729 | init_completion(&bfad->comp); | |
730 | ||
731 | /* | |
732 | * Enable Interrupt and wait bfa_init completion | |
733 | */ | |
734 | if (bfad_setup_intr(bfad)) { | |
735 | printk(KERN_WARNING "bfad%d: bfad_setup_intr failed\n", | |
736 | bfad->inst_no); | |
737 | goto out_setup_intr_failure; | |
738 | } | |
739 | ||
740 | spin_lock_irqsave(&bfad->bfad_lock, flags); | |
741 | bfa_init(&bfad->bfa); | |
742 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | |
743 | ||
744 | /* | |
745 | * Set up interrupt handler for each vectors | |
746 | */ | |
747 | if ((bfad->bfad_flags & BFAD_MSIX_ON) | |
748 | && bfad_install_msix_handler(bfad)) { | |
749 | printk(KERN_WARNING "%s: install_msix failed, bfad%d\n", | |
f8ceafde | 750 | __func__, bfad->inst_no); |
7725ccfd JH |
751 | } |
752 | ||
753 | bfad_init_timer(bfad); | |
754 | ||
755 | wait_for_completion(&bfad->comp); | |
756 | ||
757 | memset(&driver_info, 0, sizeof(driver_info)); | |
758 | strncpy(driver_info.version, BFAD_DRIVER_VERSION, | |
759 | sizeof(driver_info.version) - 1); | |
760 | if (host_name) | |
761 | strncpy(driver_info.host_machine_name, host_name, | |
762 | sizeof(driver_info.host_machine_name) - 1); | |
763 | if (os_name) | |
764 | strncpy(driver_info.host_os_name, os_name, | |
765 | sizeof(driver_info.host_os_name) - 1); | |
766 | if (os_patch) | |
767 | strncpy(driver_info.host_os_patch, os_patch, | |
768 | sizeof(driver_info.host_os_patch) - 1); | |
769 | ||
770 | strncpy(driver_info.os_device_name, bfad->pci_name, | |
771 | sizeof(driver_info.os_device_name - 1)); | |
772 | ||
773 | /* | |
774 | * FCS INIT | |
775 | */ | |
776 | spin_lock_irqsave(&bfad->bfad_lock, flags); | |
777 | bfa_fcs_log_init(&bfad->bfa_fcs, bfad->logmod); | |
778 | bfa_fcs_trc_init(&bfad->bfa_fcs, bfad->trcmod); | |
779 | bfa_fcs_aen_init(&bfad->bfa_fcs, bfad->aen); | |
82794a2e | 780 | bfa_fcs_attach(&bfad->bfa_fcs, &bfad->bfa, bfad, BFA_FALSE); |
e6714324 KG |
781 | |
782 | /* Do FCS init only when HAL init is done */ | |
783 | if ((bfad->bfad_flags & BFAD_HAL_INIT_DONE)) { | |
784 | bfa_fcs_init(&bfad->bfa_fcs); | |
785 | bfad->bfad_flags |= BFAD_FCS_INIT_DONE; | |
786 | } | |
787 | ||
7725ccfd | 788 | bfa_fcs_driver_info_init(&bfad->bfa_fcs, &driver_info); |
5b098082 | 789 | bfa_fcs_set_fdmi_param(&bfad->bfa_fcs, fdmi_enable); |
7725ccfd JH |
790 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); |
791 | ||
792 | bfad->bfad_flags |= BFAD_DRV_INIT_DONE; | |
793 | return BFA_STATUS_OK; | |
794 | ||
795 | out_setup_intr_failure: | |
796 | bfa_detach(&bfad->bfa); | |
797 | bfad_hal_mem_release(bfad); | |
798 | out_hal_mem_alloc_failure: | |
799 | return BFA_STATUS_FAILED; | |
800 | } | |
801 | ||
802 | void | |
803 | bfad_drv_uninit(struct bfad_s *bfad) | |
804 | { | |
e6714324 KG |
805 | unsigned long flags; |
806 | ||
807 | spin_lock_irqsave(&bfad->bfad_lock, flags); | |
808 | init_completion(&bfad->comp); | |
809 | bfa_stop(&bfad->bfa); | |
810 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | |
811 | wait_for_completion(&bfad->comp); | |
812 | ||
7725ccfd JH |
813 | del_timer_sync(&bfad->hal_tmo); |
814 | bfa_isr_disable(&bfad->bfa); | |
815 | bfa_detach(&bfad->bfa); | |
816 | bfad_remove_intr(bfad); | |
7725ccfd | 817 | bfad_hal_mem_release(bfad); |
e6714324 KG |
818 | |
819 | bfad->bfad_flags &= ~BFAD_DRV_INIT_DONE; | |
7725ccfd JH |
820 | } |
821 | ||
822 | void | |
823 | bfad_drv_start(struct bfad_s *bfad) | |
824 | { | |
825 | unsigned long flags; | |
826 | ||
827 | spin_lock_irqsave(&bfad->bfad_lock, flags); | |
828 | bfa_start(&bfad->bfa); | |
829 | bfa_fcs_start(&bfad->bfa_fcs); | |
830 | bfad->bfad_flags |= BFAD_HAL_START_DONE; | |
831 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | |
832 | ||
833 | bfad_fc4_probe_post(bfad); | |
834 | } | |
835 | ||
836 | void | |
837 | bfad_drv_stop(struct bfad_s *bfad) | |
838 | { | |
839 | unsigned long flags; | |
840 | ||
841 | spin_lock_irqsave(&bfad->bfad_lock, flags); | |
842 | init_completion(&bfad->comp); | |
843 | bfad->pport.flags |= BFAD_PORT_DELETE; | |
844 | bfa_fcs_exit(&bfad->bfa_fcs); | |
845 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | |
846 | wait_for_completion(&bfad->comp); | |
847 | ||
848 | spin_lock_irqsave(&bfad->bfad_lock, flags); | |
849 | init_completion(&bfad->comp); | |
850 | bfa_stop(&bfad->bfa); | |
851 | bfad->bfad_flags &= ~BFAD_HAL_START_DONE; | |
852 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | |
853 | wait_for_completion(&bfad->comp); | |
854 | } | |
855 | ||
856 | bfa_status_t | |
857 | bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role) | |
858 | { | |
859 | int rc = BFA_STATUS_OK; | |
860 | ||
861 | /* | |
862 | * Allocate scsi_host for the physical port | |
863 | */ | |
864 | if ((bfad_supported_fc4s & BFA_PORT_ROLE_FCP_IM) | |
865 | && (role & BFA_PORT_ROLE_FCP_IM)) { | |
866 | if (bfad->pport.im_port == NULL) { | |
867 | rc = BFA_STATUS_FAILED; | |
868 | goto out; | |
869 | } | |
870 | ||
b504293f JH |
871 | rc = bfad_im_scsi_host_alloc(bfad, bfad->pport.im_port, |
872 | &bfad->pcidev->dev); | |
7725ccfd JH |
873 | if (rc != BFA_STATUS_OK) |
874 | goto out; | |
875 | ||
876 | bfad->pport.roles |= BFA_PORT_ROLE_FCP_IM; | |
877 | } | |
878 | ||
879 | bfad->bfad_flags |= BFAD_CFG_PPORT_DONE; | |
880 | ||
881 | out: | |
882 | return rc; | |
883 | } | |
884 | ||
885 | void | |
886 | bfad_uncfg_pport(struct bfad_s *bfad) | |
887 | { | |
888 | if ((bfad->pport.roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) { | |
889 | bfad_ipfc_port_delete(bfad, &bfad->pport); | |
890 | bfad->pport.roles &= ~BFA_PORT_ROLE_FCP_IPFC; | |
891 | } | |
892 | ||
893 | if ((bfad_supported_fc4s & BFA_PORT_ROLE_FCP_IM) | |
894 | && (bfad->pport.roles & BFA_PORT_ROLE_FCP_IM)) { | |
895 | bfad_im_scsi_host_free(bfad, bfad->pport.im_port); | |
896 | bfad_im_port_clean(bfad->pport.im_port); | |
897 | kfree(bfad->pport.im_port); | |
898 | bfad->pport.roles &= ~BFA_PORT_ROLE_FCP_IM; | |
899 | } | |
900 | ||
901 | bfad->bfad_flags &= ~BFAD_CFG_PPORT_DONE; | |
902 | } | |
903 | ||
904 | void | |
905 | bfad_drv_log_level_set(struct bfad_s *bfad) | |
906 | { | |
907 | if (log_level > BFA_LOG_INVALID && log_level <= BFA_LOG_LEVEL_MAX) | |
908 | bfa_log_set_level_all(&bfad->log_data, log_level); | |
909 | } | |
910 | ||
e6714324 KG |
911 | bfa_status_t |
912 | bfad_start_ops(struct bfad_s *bfad) | |
913 | { | |
914 | int retval; | |
d9883548 | 915 | struct bfad_pcfg_s *pcfg, *pcfg_new; |
e6714324 KG |
916 | |
917 | /* PPORT FCS config */ | |
918 | bfad_fcs_port_cfg(bfad); | |
919 | ||
920 | retval = bfad_cfg_pport(bfad, BFA_PORT_ROLE_FCP_IM); | |
921 | if (retval != BFA_STATUS_OK) | |
922 | goto out_cfg_pport_failure; | |
923 | ||
924 | /* BFAD level FC4 (IM/TM/IPFC) specific resource allocation */ | |
925 | retval = bfad_fc4_probe(bfad); | |
926 | if (retval != BFA_STATUS_OK) { | |
927 | printk(KERN_WARNING "bfad_fc4_probe failed\n"); | |
928 | goto out_fc4_probe_failure; | |
929 | } | |
930 | ||
931 | bfad_drv_start(bfad); | |
932 | ||
d9883548 JH |
933 | /* pbc vport creation */ |
934 | list_for_each_entry_safe(pcfg, pcfg_new, &bfad->pbc_pcfg_list, | |
935 | list_entry) { | |
936 | struct fc_vport_identifiers vid; | |
937 | struct fc_vport *fc_vport; | |
938 | ||
939 | memset(&vid, 0, sizeof(vid)); | |
940 | vid.roles = FC_PORT_ROLE_FCP_INITIATOR; | |
941 | vid.vport_type = FC_PORTTYPE_NPIV; | |
942 | vid.disable = false; | |
943 | vid.node_name = wwn_to_u64((u8 *)&pcfg->port_cfg.nwwn); | |
944 | vid.port_name = wwn_to_u64((u8 *)&pcfg->port_cfg.pwwn); | |
945 | fc_vport = fc_vport_create(bfad->pport.im_port->shost, 0, &vid); | |
946 | if (!fc_vport) | |
947 | printk(KERN_WARNING "bfad%d: failed to create pbc vport" | |
948 | " %llx\n", bfad->inst_no, vid.port_name); | |
949 | list_del(&pcfg->list_entry); | |
950 | kfree(pcfg); | |
951 | ||
952 | } | |
953 | ||
e6714324 KG |
954 | /* |
955 | * If bfa_linkup_delay is set to -1 default; try to retrive the | |
956 | * value using the bfad_os_get_linkup_delay(); else use the | |
957 | * passed in module param value as the bfa_linkup_delay. | |
958 | */ | |
959 | if (bfa_linkup_delay < 0) { | |
960 | ||
961 | bfa_linkup_delay = bfad_os_get_linkup_delay(bfad); | |
962 | bfad_os_rport_online_wait(bfad); | |
963 | bfa_linkup_delay = -1; | |
964 | ||
965 | } else { | |
966 | bfad_os_rport_online_wait(bfad); | |
967 | } | |
968 | ||
969 | bfa_log(bfad->logmod, BFA_LOG_LINUX_DEVICE_CLAIMED, bfad->pci_name); | |
970 | ||
971 | return BFA_STATUS_OK; | |
972 | ||
973 | out_fc4_probe_failure: | |
974 | bfad_fc4_probe_undo(bfad); | |
975 | bfad_uncfg_pport(bfad); | |
976 | out_cfg_pport_failure: | |
977 | return BFA_STATUS_FAILED; | |
978 | } | |
979 | ||
980 | int | |
d9883548 | 981 | bfad_worker(void *ptr) |
e6714324 KG |
982 | { |
983 | struct bfad_s *bfad; | |
984 | unsigned long flags; | |
985 | ||
986 | bfad = (struct bfad_s *)ptr; | |
987 | ||
988 | while (!kthread_should_stop()) { | |
989 | ||
990 | /* Check if the FCS init is done from bfad_drv_init; | |
991 | * if not done do FCS init and set the flag. | |
992 | */ | |
993 | if (!(bfad->bfad_flags & BFAD_FCS_INIT_DONE)) { | |
994 | spin_lock_irqsave(&bfad->bfad_lock, flags); | |
995 | bfa_fcs_init(&bfad->bfa_fcs); | |
996 | bfad->bfad_flags |= BFAD_FCS_INIT_DONE; | |
997 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | |
998 | } | |
999 | ||
1000 | /* Start the bfad operations after HAL init done */ | |
1001 | bfad_start_ops(bfad); | |
1002 | ||
1003 | spin_lock_irqsave(&bfad->bfad_lock, flags); | |
1004 | bfad->bfad_tsk = NULL; | |
1005 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | |
1006 | ||
1007 | break; | |
1008 | } | |
1009 | ||
1010 | return 0; | |
1011 | } | |
1012 | ||
7725ccfd JH |
1013 | /* |
1014 | * PCI_entry PCI driver entries * { | |
1015 | */ | |
1016 | ||
1017 | /** | |
1018 | * PCI probe entry. | |
1019 | */ | |
1020 | int | |
1021 | bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) | |
1022 | { | |
1023 | struct bfad_s *bfad; | |
1024 | int error = -ENODEV, retval; | |
7725ccfd JH |
1025 | |
1026 | /* | |
1027 | * For single port cards - only claim function 0 | |
1028 | */ | |
1029 | if ((pdev->device == BFA_PCI_DEVICE_ID_FC_8G1P) | |
1030 | && (PCI_FUNC(pdev->devfn) != 0)) | |
1031 | return -ENODEV; | |
1032 | ||
1033 | BFA_TRACE(BFA_INFO, "bfad_pci_probe entry"); | |
1034 | ||
1035 | bfad = kzalloc(sizeof(struct bfad_s), GFP_KERNEL); | |
1036 | if (!bfad) { | |
1037 | error = -ENOMEM; | |
1038 | goto out; | |
1039 | } | |
1040 | ||
1041 | bfad->trcmod = kzalloc(sizeof(struct bfa_trc_mod_s), GFP_KERNEL); | |
1042 | if (!bfad->trcmod) { | |
1043 | printk(KERN_WARNING "Error alloc trace buffer!\n"); | |
1044 | error = -ENOMEM; | |
1045 | goto out_alloc_trace_failure; | |
1046 | } | |
1047 | ||
1048 | /* | |
1049 | * LOG/TRACE INIT | |
1050 | */ | |
1051 | bfa_trc_init(bfad->trcmod); | |
1052 | bfa_trc(bfad, bfad_inst); | |
1053 | ||
1054 | bfad->logmod = &bfad->log_data; | |
0a4b1fc0 | 1055 | bfa_log_init(bfad->logmod, (char *)pci_name(pdev), bfa_os_printf); |
7725ccfd JH |
1056 | |
1057 | bfad_drv_log_level_set(bfad); | |
1058 | ||
1059 | bfad->aen = &bfad->aen_buf; | |
1060 | ||
1061 | if (!(bfad_load_fwimg(pdev))) { | |
1062 | printk(KERN_WARNING "bfad_load_fwimg failure!\n"); | |
1063 | kfree(bfad->trcmod); | |
1064 | goto out_alloc_trace_failure; | |
1065 | } | |
1066 | ||
1067 | retval = bfad_pci_init(pdev, bfad); | |
1068 | if (retval) { | |
1069 | printk(KERN_WARNING "bfad_pci_init failure!\n"); | |
1070 | error = retval; | |
1071 | goto out_pci_init_failure; | |
1072 | } | |
1073 | ||
1074 | mutex_lock(&bfad_mutex); | |
1075 | bfad->inst_no = bfad_inst++; | |
1076 | list_add_tail(&bfad->list_entry, &bfad_list); | |
1077 | mutex_unlock(&bfad_mutex); | |
1078 | ||
1079 | spin_lock_init(&bfad->bfad_lock); | |
1080 | pci_set_drvdata(pdev, bfad); | |
1081 | ||
1082 | bfad->ref_count = 0; | |
1083 | bfad->pport.bfad = bfad; | |
d9883548 | 1084 | INIT_LIST_HEAD(&bfad->pbc_pcfg_list); |
7725ccfd | 1085 | |
e6714324 KG |
1086 | bfad->bfad_tsk = kthread_create(bfad_worker, (void *) bfad, "%s", |
1087 | "bfad_worker"); | |
1088 | if (IS_ERR(bfad->bfad_tsk)) { | |
1089 | printk(KERN_INFO "bfad[%d]: Kernel thread" | |
1090 | " creation failed!\n", | |
1091 | bfad->inst_no); | |
1092 | goto out_kthread_create_failure; | |
1093 | } | |
1094 | ||
7725ccfd JH |
1095 | retval = bfad_drv_init(bfad); |
1096 | if (retval != BFA_STATUS_OK) | |
1097 | goto out_drv_init_failure; | |
1098 | if (!(bfad->bfad_flags & BFAD_HAL_INIT_DONE)) { | |
e6714324 | 1099 | bfad->bfad_flags |= BFAD_HAL_INIT_FAIL; |
7725ccfd JH |
1100 | printk(KERN_WARNING "bfad%d: hal init failed\n", bfad->inst_no); |
1101 | goto ok; | |
1102 | } | |
1103 | ||
e6714324 | 1104 | retval = bfad_start_ops(bfad); |
7725ccfd | 1105 | if (retval != BFA_STATUS_OK) |
e6714324 | 1106 | goto out_start_ops_failure; |
7725ccfd | 1107 | |
e6714324 KG |
1108 | kthread_stop(bfad->bfad_tsk); |
1109 | bfad->bfad_tsk = NULL; | |
7725ccfd | 1110 | |
7725ccfd JH |
1111 | ok: |
1112 | return 0; | |
1113 | ||
e6714324 | 1114 | out_start_ops_failure: |
7725ccfd JH |
1115 | bfad_drv_uninit(bfad); |
1116 | out_drv_init_failure: | |
e6714324 KG |
1117 | kthread_stop(bfad->bfad_tsk); |
1118 | out_kthread_create_failure: | |
7725ccfd JH |
1119 | mutex_lock(&bfad_mutex); |
1120 | bfad_inst--; | |
1121 | list_del(&bfad->list_entry); | |
1122 | mutex_unlock(&bfad_mutex); | |
1123 | bfad_pci_uninit(pdev, bfad); | |
1124 | out_pci_init_failure: | |
1125 | kfree(bfad->trcmod); | |
1126 | out_alloc_trace_failure: | |
1127 | kfree(bfad); | |
1128 | out: | |
1129 | return error; | |
1130 | } | |
1131 | ||
1132 | /** | |
1133 | * PCI remove entry. | |
1134 | */ | |
1135 | void | |
1136 | bfad_pci_remove(struct pci_dev *pdev) | |
1137 | { | |
1138 | struct bfad_s *bfad = pci_get_drvdata(pdev); | |
1139 | unsigned long flags; | |
1140 | ||
1141 | bfa_trc(bfad, bfad->inst_no); | |
1142 | ||
e6714324 KG |
1143 | spin_lock_irqsave(&bfad->bfad_lock, flags); |
1144 | if (bfad->bfad_tsk != NULL) | |
1145 | kthread_stop(bfad->bfad_tsk); | |
1146 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | |
1147 | ||
7725ccfd JH |
1148 | if ((bfad->bfad_flags & BFAD_DRV_INIT_DONE) |
1149 | && !(bfad->bfad_flags & BFAD_HAL_INIT_DONE)) { | |
1150 | ||
1151 | spin_lock_irqsave(&bfad->bfad_lock, flags); | |
1152 | init_completion(&bfad->comp); | |
1153 | bfa_stop(&bfad->bfa); | |
1154 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | |
1155 | wait_for_completion(&bfad->comp); | |
1156 | ||
1157 | bfad_remove_intr(bfad); | |
1158 | del_timer_sync(&bfad->hal_tmo); | |
1159 | goto hal_detach; | |
1160 | } else if (!(bfad->bfad_flags & BFAD_DRV_INIT_DONE)) { | |
1161 | goto remove_sysfs; | |
1162 | } | |
1163 | ||
e6714324 | 1164 | if (bfad->bfad_flags & BFAD_HAL_START_DONE) { |
7725ccfd | 1165 | bfad_drv_stop(bfad); |
e6714324 KG |
1166 | } else if (bfad->bfad_flags & BFAD_DRV_INIT_DONE) { |
1167 | /* Invoking bfa_stop() before bfa_detach | |
1168 | * when HAL and DRV init are success | |
1169 | * but HAL start did not occur. | |
1170 | */ | |
1171 | spin_lock_irqsave(&bfad->bfad_lock, flags); | |
1172 | init_completion(&bfad->comp); | |
1173 | bfa_stop(&bfad->bfa); | |
1174 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | |
1175 | wait_for_completion(&bfad->comp); | |
1176 | } | |
7725ccfd JH |
1177 | |
1178 | bfad_remove_intr(bfad); | |
7725ccfd | 1179 | del_timer_sync(&bfad->hal_tmo); |
e6714324 KG |
1180 | |
1181 | if (bfad->bfad_flags & BFAD_FC4_PROBE_DONE) | |
1182 | bfad_fc4_probe_undo(bfad); | |
7725ccfd JH |
1183 | |
1184 | if (bfad->bfad_flags & BFAD_CFG_PPORT_DONE) | |
1185 | bfad_uncfg_pport(bfad); | |
1186 | ||
1187 | hal_detach: | |
1188 | spin_lock_irqsave(&bfad->bfad_lock, flags); | |
1189 | bfa_detach(&bfad->bfa); | |
1190 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | |
1191 | bfad_hal_mem_release(bfad); | |
1192 | remove_sysfs: | |
1193 | ||
1194 | mutex_lock(&bfad_mutex); | |
1195 | bfad_inst--; | |
1196 | list_del(&bfad->list_entry); | |
1197 | mutex_unlock(&bfad_mutex); | |
1198 | bfad_pci_uninit(pdev, bfad); | |
1199 | ||
1200 | kfree(bfad->trcmod); | |
1201 | kfree(bfad); | |
1202 | } | |
1203 | ||
1204 | ||
1205 | static struct pci_device_id bfad_id_table[] = { | |
1206 | { | |
1207 | .vendor = BFA_PCI_VENDOR_ID_BROCADE, | |
1208 | .device = BFA_PCI_DEVICE_ID_FC_8G2P, | |
1209 | .subvendor = PCI_ANY_ID, | |
1210 | .subdevice = PCI_ANY_ID, | |
1211 | }, | |
1212 | { | |
1213 | .vendor = BFA_PCI_VENDOR_ID_BROCADE, | |
1214 | .device = BFA_PCI_DEVICE_ID_FC_8G1P, | |
1215 | .subvendor = PCI_ANY_ID, | |
1216 | .subdevice = PCI_ANY_ID, | |
1217 | }, | |
1218 | { | |
1219 | .vendor = BFA_PCI_VENDOR_ID_BROCADE, | |
1220 | .device = BFA_PCI_DEVICE_ID_CT, | |
1221 | .subvendor = PCI_ANY_ID, | |
1222 | .subdevice = PCI_ANY_ID, | |
1223 | .class = (PCI_CLASS_SERIAL_FIBER << 8), | |
1224 | .class_mask = ~0, | |
1225 | }, | |
293f82d5 JH |
1226 | { |
1227 | .vendor = BFA_PCI_VENDOR_ID_BROCADE, | |
1228 | .device = BFA_PCI_DEVICE_ID_CT_FC, | |
1229 | .subvendor = PCI_ANY_ID, | |
1230 | .subdevice = PCI_ANY_ID, | |
1231 | .class = (PCI_CLASS_SERIAL_FIBER << 8), | |
1232 | .class_mask = ~0, | |
1233 | }, | |
7725ccfd JH |
1234 | |
1235 | {0, 0}, | |
1236 | }; | |
1237 | ||
1238 | MODULE_DEVICE_TABLE(pci, bfad_id_table); | |
1239 | ||
1240 | static struct pci_driver bfad_pci_driver = { | |
1241 | .name = BFAD_DRIVER_NAME, | |
1242 | .id_table = bfad_id_table, | |
1243 | .probe = bfad_pci_probe, | |
1244 | .remove = __devexit_p(bfad_pci_remove), | |
1245 | }; | |
1246 | ||
1247 | /** | |
1248 | * Linux driver module functions | |
1249 | */ | |
1250 | bfa_status_t | |
1251 | bfad_fc4_module_init(void) | |
1252 | { | |
1253 | int rc; | |
1254 | ||
1255 | rc = bfad_im_module_init(); | |
1256 | if (rc != BFA_STATUS_OK) | |
1257 | goto ext; | |
1258 | ||
1259 | bfad_tm_module_init(); | |
1260 | if (ipfc_enable) | |
1261 | bfad_ipfc_module_init(); | |
1262 | ext: | |
1263 | return rc; | |
1264 | } | |
1265 | ||
1266 | void | |
1267 | bfad_fc4_module_exit(void) | |
1268 | { | |
1269 | if (ipfc_enable) | |
1270 | bfad_ipfc_module_exit(); | |
1271 | bfad_tm_module_exit(); | |
1272 | bfad_im_module_exit(); | |
1273 | } | |
1274 | ||
1275 | /** | |
1276 | * Driver module init. | |
1277 | */ | |
1278 | static int __init | |
1279 | bfad_init(void) | |
1280 | { | |
1281 | int error = 0; | |
1282 | ||
1283 | printk(KERN_INFO "Brocade BFA FC/FCOE SCSI driver - version: %s\n", | |
1284 | BFAD_DRIVER_VERSION); | |
1285 | ||
1286 | if (num_sgpgs > 0) | |
1287 | num_sgpgs_parm = num_sgpgs; | |
1288 | ||
1289 | error = bfad_fc4_module_init(); | |
1290 | if (error) { | |
1291 | error = -ENOMEM; | |
1292 | printk(KERN_WARNING "bfad_fc4_module_init failure\n"); | |
1293 | goto ext; | |
1294 | } | |
1295 | ||
1296 | if (!strcmp(FCPI_NAME, " fcpim")) | |
1297 | bfad_supported_fc4s |= BFA_PORT_ROLE_FCP_IM; | |
1298 | if (!strcmp(FCPT_NAME, " fcptm")) | |
1299 | bfad_supported_fc4s |= BFA_PORT_ROLE_FCP_TM; | |
1300 | if (!strcmp(IPFC_NAME, " ipfc")) | |
1301 | bfad_supported_fc4s |= BFA_PORT_ROLE_FCP_IPFC; | |
1302 | ||
1303 | bfa_ioc_auto_recover(ioc_auto_recover); | |
1304 | bfa_fcs_rport_set_del_timeout(rport_del_timeout); | |
1305 | error = pci_register_driver(&bfad_pci_driver); | |
1306 | ||
1307 | if (error) { | |
1308 | printk(KERN_WARNING "bfad pci_register_driver failure\n"); | |
1309 | goto ext; | |
1310 | } | |
1311 | ||
1312 | return 0; | |
1313 | ||
1314 | ext: | |
1315 | bfad_fc4_module_exit(); | |
1316 | return error; | |
1317 | } | |
1318 | ||
1319 | /** | |
1320 | * Driver module exit. | |
1321 | */ | |
1322 | static void __exit | |
1323 | bfad_exit(void) | |
1324 | { | |
1325 | pci_unregister_driver(&bfad_pci_driver); | |
1326 | bfad_fc4_module_exit(); | |
1327 | bfad_free_fwimg(); | |
1328 | } | |
1329 | ||
1330 | #define BFAD_PROTO_NAME FCPI_NAME FCPT_NAME IPFC_NAME | |
1331 | ||
1332 | module_init(bfad_init); | |
1333 | module_exit(bfad_exit); | |
1334 | MODULE_LICENSE("GPL"); | |
1335 | MODULE_DESCRIPTION("Brocade Fibre Channel HBA Driver" BFAD_PROTO_NAME); | |
1336 | MODULE_AUTHOR("Brocade Communications Systems, Inc."); | |
1337 | MODULE_VERSION(BFAD_DRIVER_VERSION); | |
1338 | ||
1339 |